java接入微信支付
首先有两个东西,一个叫商户平台(),一个叫合作伙伴平台(),一定要分清是哪一个,因为他们接口不一样。我用的是商户平台,支付有很多封装好的工具包,直接用。
·
首先有两个东西,它们接口参数是不一样的
一个叫商户平台( https://pay.weixin.qq.com/),没有子商户
一个叫合作伙伴平台( https://pay.weixin.qq.com/index.php/partner/public/home),有主商户和子商户
一定要分清是哪一个,因为他们接口不一样。
我用的是商户平台,支付有很多封装好的工具包,直接用。
流程
[用户提交订单]
↓
[服务端生成订单(out_trade_no)并调用统一下单接口(prepay_id)]
↓
[服务端封装 prepay_id 生成调起支付参数返回给前端]
↓
[前端调起微信支付(基于 prepay_id)]
↓
[用户完成支付]
↓
[微信回调通知服务器(支付成功)]
↓
[服务器验签 + 记录支付状态]
JPay
引入依赖
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-All</artifactId>
<version>2.9.11</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>com.github.xkzhangsan</groupId>
<artifactId>xk-time</artifactId>
<version>3.0.1</version>
</dependency>
从证书中获取序列号
/**
* 从整数中获取证书序列号
* @return
* @throws Exception
*/
public String getSerialNumber() throws Exception {
X509Certificate certificate = PayKit.getCertificate("D:\\cert\\apiclient_cert.pem");
String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase(Locale.getDefault());
return serialNumber;
}
下单
import com.alibaba.fastjson2.JSONObject;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.utils.DateTimeZoneUtil;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxApiType;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.model.v3.Amount;
import com.ijpay.wxpay.model.v3.UnifiedOrderModel;
import java.security.cert.X509Certificate;
import java.util.Locale;
public class TestPay {
public static void main(String[] args) throws Exception{
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel();
//appid
unifiedOrderModel.setAppid("");
//mchid
unifiedOrderModel.setMchid("");
//描述
unifiedOrderModel.setDescription("111111");
//商户系统内部订单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款号下不可重复使用。
unifiedOrderModel.setOut_trade_no("12323213");
//订单失效时间
unifiedOrderModel.setTime_expire(DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 15));
JSONObject attach = new JSONObject();
attach.put("tradeNo", "1232132132");
//附加数据,支付成功后查询订单API和支付成功回调通知均会将此字段返回给商户
unifiedOrderModel.setAttach(JSONObject.toJSONString(attach));
//支付成功的回调地址
unifiedOrderModel.setNotify_url("https://www.baidu.com");
Amount amount = new Amount();
amount.setTotal(1);
unifiedOrderModel.setAmount(amount);
//订单金额,单位为分,整型
String unifiedOrderData = JSONObject.toJSONString(unifiedOrderModel);
//获取证书序列号
X509Certificate certificate = PayKit.getCertificate("D:\\cert\\apiclient_cert.pem");
String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase(Locale.getDefault());
//发起请求
IJPayHttpResponse payResponse = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
WxApiType.APP_PAY.toString(),
appid,
serialNumber,
null,
"D:\\cert\\apiclient_key.pem",
unifiedOrderData
);
System.out.println(payResponse);
}
}
IJPayHttpResponse{body='{"prepay_id":"wx251746560968658bf5a732a819c00a0001"}', status=200
根据out_trade_no查询订单
/**
* 商户订单号查询订单
* out_trade_no
* @throws Exception
*/
@Test
public void test2() throws Exception {
Map<String, String> params = new HashMap<>(16);
params.put("mchid", "mchid");
IJPayHttpResponse ijPayHttpResponse = WxPayApi.v3(
RequestMethodEnum.GET,
WxDomainEnum.CHINA.toString(),
String.format(BasePayApiEnum.ORDER_QUERY_BY_OUT_TRADE_NO.toString(),12323213),
"mchid",
getSerialNumber(),
null,
"D:\\mchid_20240816_cert\\apiclient_key.pem",
params
);
System.out.println(ijPayHttpResponse);
}
IJPayHttpResponse{body='{"amount":{"payer_currency":"CNY","total":1},"appid":"","mchid":"","out_trade_no":"12323213","promotion_detail":[],"scene_info":{"device_id":""},"trade_state":"NOTPAY","trade_state_desc":"订单未支付"}', status=200
支付回调
@RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public void payNotify(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> map = new HashMap<>(12);
try {
String timestamp = request.getHeader("Wechatpay-Timestamp");
String nonce = request.getHeader("Wechatpay-Nonce");
String serialNo = request.getHeader("Wechatpay-Serial");
String signature = request.getHeader("Wechatpay-Signature");
log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
String result = HttpKit.readData(request);
log.info("支付通知密文 {}", result);
String plainText = null;
// 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
// String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
// wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
// 微信公钥验证签名并解密
if (StringUtils.equals(serialNo, wxPayV3Bean.getPublicKeyId())) {
plainText = WxPayKit.verifyPublicKeyNotify(result, signature, nonce, timestamp,
wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
}
log.info("支付通知明文 {}", plainText);
if (StrUtil.isNotEmpty(plainText)) {
response.setStatus(200);
map.put("code", "SUCCESS");
map.put("message", "SUCCESS");
} else {
response.setStatus(500);
map.put("code", "ERROR");
map.put("message", "签名错误");
}
response.setHeader("Content-type", ContentType.JSON.toString());
response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
} catch (Exception e) {
log.error("系统异常", e);
}
}
协议错误
SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at com.ijpay.core.http.AbstractHttpDelegate.post(AbstractHttpDelegate.java:297)
at com.ijpay.core.http.AbstractHttpDelegate.post(AbstractHttpDelegate.java:312)

其它
商户订单号重复
每次发送请求唤起支付,out_trade_no只能唯一。除非金额和其它项没有变,就可以继续使用同一个out_trade_no进行支付请求。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)