流程概要
1、小程序传递订单参数调用后端的支付订单接口 2、后端接口调用微信支付系统后生成6个必要参数返回给小程序 3、小程序调用wx.requestPayment拉起微信支付 4、用户支付后,微信支付系统调用后端回调接口 5、后端回调接口对具体的业务逻辑进行处理
官方接口文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
添加Maven依赖
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-All</artifactId>
<version>2.7.4</version>
</dependency>
平台证书的生成
平台证书是必须的,生成方法: 参考整理的另一篇笔记:https://blog.csdn.net/Yisermorn/article/details/127304729?spm=1001.2014.3001.5502
创建通用参数文件 weChatPay.properties
文件存放路径:src\main\resources\
v3.keyPath=opt/.../apiclient_key.pem
v3.certPath=opt/.../apiclient_cert.pem
v3.certP12Path=opt/.../apiclient_cert.p12
v3.platformCertPath=opy/.../wx_cert.pem
v3.mchId=
v3.apiKey=
v3.apiKey3=
v3.domain=
v3.AppId=
v3.AppSecret=
创建通用参数类 WxPay
将properties文件中属性的值赋值到WxPay类中
@Data
@Component
@PropertySource("classpath:weChatPay.properties")
@ConfigurationProperties(prefix = "v3")
public class WxPay {
private String keyPath;
private String certPath;
private String certP12Path;
private String platformCertPath;
private String mchId;
private String apiKey;
private String apiKey3;
private String domain;
private String AppId;
private String AppSecret;
}
编写控制层代码
创建Controller类编写 获取微信支付唤起参数 接口
@GetMapping(value = "/jsapiPay")
public Object jsapiPay(String orderNumber){
try {
return wxPayService.jsapiPay(orderNumber);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@RequestMapping("/payNotify")
public void payNotify(HttpServletRequest request, HttpServletResponse response) {
wxPayService.payNotify(request,response);
}
编写服务层代码
略过service层方法接口,展示的是方法的实现
@Override
public Map<String, String> jsapiPay(String orderNumber) throws Exception{
Order order = orderMapper.selectOneByOrderNumber(orderNumber);
String openId = ;
Integer price = 1;
String timeExpire = Utils.rfc3339.format( new Date(System.currentTimeMillis()+1000*60*5) );
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
.setAppid( wxPay.getAppId() )
.setMchid( wxPay.getMchId() )
.setDescription( "描述" )
.setOut_trade_no( orderNumber )
.setTime_expire(timeExpire)
.setAttach( "附加数据" )
.setNotify_url(wxPay.getDomain().concat("/weChatPay/payNotify"))
.setAmount(new Amount().setTotal(price))
.setPayer(new Payer().setOpenid(openId));
logger.info("订单创建参数:"+ JSONUtil.toJsonStr(unifiedOrderModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethod.POST,
WxDomain.CHINA.toString(),
WxApiType.JS_API_PAY.toString(),
wxPay.getMchId(),
getSerialNumber(),
null,
wxPay.getKeyPath(),
JSONUtil.toJsonStr(unifiedOrderModel)
);
logger.info("统一下单响应:{}", response.toString());
if ( response.getStatus()==200 ) {
boolean verifySignature = WxPayKit.verifySignature(response, wxPay.getPlatformCertPath());
logger.info("verifySignature: {}", verifySignature);
if (verifySignature) {
String body = response.getBody();
JSONObject jsonObject = JSONUtil.parseObj(body);
String prepayId = jsonObject.getStr("prepay_id");
Map<String, String> map = WxPayKit.jsApiCreateSign(wxPay.getAppId(), prepayId, wxPay.getKeyPath());
logger.info("唤起支付参数:{}", map);
return map;
}
}
return null;
}
@Override
public void payNotify(HttpServletRequest request, HttpServletResponse response) {
logger.info("收到微信支付回调");
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");
logger.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
String result = HttpKit.readData(request);
logger.info("支付通知密文: {}", result);
String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
wxPay.getApiKey3(), wxPay.getPlatformCertPath());
logger.info("支付通知明文 {}", plainText);
savePayPlainText(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) {
e.printStackTrace();
}
}
private String getSerialNumber() throws IOException {
String certPath = wxPay.getCertPath();
logger.info("path:{}", certPath);
X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(certPath));
String serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
logger.info("获取证书序列号:{},", serialNo);
return serialNo;
}
private void savePayPlainText(String plainText) {
JSONObject jsonObject = JSONUtil.parseObj(plainText);
String outTradeNo = jsonObject.getStr("out_trade_no");
}
退款接口的控制层代码
@GetMapping(value = "/payRefund")
public String payRefund(String transactionId, String outTradeNo) {
return wxPayService.payRefund(transactionId, outTradeNo);
}
退款接口的服务层代码
@Override
public String payRefund(String transactionId, String outTradeNo) {
logger.info("进入退款接口------>" );
logger.info("执行操作的 原支付交易对应的微信订单号:{}", transactionId);
logger.info("执行操作的 原支付交易对应的商户订单号:{}", outTradeNo );
try {
String outRefundNo = PayKit.generateStr();
logger.info("商户退款单号: {}", outRefundNo);
List<RefundGoodsDetail> list = new ArrayList<>();
RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
.setMerchant_goods_id( outRefundNo )
.setGoods_name( "取消订单" )
.setUnit_price( 1 )
.setRefund_amount( 1 )
.setRefund_quantity(1);
list.add(refundGoodsDetail);
RefundModel refundModel = new RefundModel()
.setOut_refund_no(outRefundNo)
.setReason("取消订单")
.setAmount(new RefundAmount().setRefund(1).setTotal(1).setCurrency("CNY"))
.setGoods_detail(list);
if (transactionId!=null && !transactionId.equals("")) {
refundModel.setTransaction_id(transactionId);
}
if (outTradeNo!=null && !outTradeNo.equals("")) {
refundModel.setOut_trade_no( outTradeNo );
}
logger.info("退款参数: {}", JSONUtil.toJsonStr(refundModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethod.POST,
WxDomain.CHINA.toString(),
WxApiType.DOMESTIC_REFUNDS.toString(),
wxPay.getMchId(),
getSerialNumber(),
null,
wxPay.getKeyPath(),
JSONUtil.toJsonStr(refundModel)
);
logger.info("退款响应 {}", response);
boolean verifySignature = WxPayKit.verifySignature(response, wxPay.getPlatformCertPath());
logger.info("verifySignature: {}", verifySignature);
String body = response.getBody();
JSONObject jsonObject = JSONUtil.parseObj(body);
if(response.getStatus()==200){
}
if (verifySignature) {
return response.getBody();
}
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
return null;
}
|