微信支付接口接入
微信支付接入文档参考(https://pay.weixin.qq.com/docs/merchant/products/jsapi-payment/preparation.html)
1. 接入前准备
具体步骤如下所示:
1、选择接入模式:普通商户或普通服务商, 官网说明地址:https://pay.weixin.qq.com/docs/merchant/development/glossary/mode.html
2、申请参数:AppID、商户号
申请接入微信支付:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/index.shtml , 按照指引提交相关资料等待审核。
资料审核通过以后会获取商户的相关信息(商户id、API v3密钥、商户API证书) , 这些信息在支付的时候需要使用到。
3、配置应用:https://pay.weixin.qq.com/docs/merchant/products/jsapi-payment/preparation.html
相关说明: 微信支付支付多种支付方式,本次我们选择的支付方式为JSAPI支付,属于C扫B方式。
微信支付相关API
JSAPI下单接口:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/direct-jsons/jsapi-prepay.html
JSAPI调起支付接口:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/jsapi-transfer-payment.html
SDK和示例Demo:https://pay.weixin.qq.com/docs/merchant/sdk-tools/quickstart-java.html
关于JSAPI下单接口和JSAPI调起支付接口有什么区别?
2. 微信下单接口
参考API文档开发微信下单接口
接口说明:
支持商户:【普通商户】
请求方式:【POST】/v3/pay/transactions/jsapi
请求域名:【主域名】https://api.mch.weixin.qq.com 使用该域名将访问就近的接入点
请求参数:
HTTP请求头
**Authorization **必填string
请参考 签名认证 生成认证信息
Accept必填string
请设置为 application/json
Content-Type必填string
请设置为 application/json
HTTP请求体
appid必填string(32)
【公众号ID】 公众号ID
mchid必填string(32)
【直连商户号】 直连商户号
description必填string(127)
【商品描述】 商品描述
out_trade_no必填string(32)
【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
notify_url必填string(255)
【通知地址】 异步接收微信支付结果通知的回调地址,通知URL必须为外网可访问的URL,不能携带参数。 公网域名必须为HTTPS,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用HTTP
amount必填object
【订单金额】 订单金额
payer必填object
【支付者】 支付者信息
请求示例
curl -X POST
https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
-H "Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900000001",..."
-H "Accept: application/json"
-H "Content-Type: application/json"
-d '{
"appid" : "wxd678efh567hg6787",
"mchid" : "1230000109",
"description" : "Image形象店-深圳腾大-QQ公仔",
"out_trade_no" : "1217752501201407033233368018",
"time_expire" : "2018-06-08T10:34:56+08:00",
"attach" : "自定义数据说明",
"notify_url" : " https://www.weixin.qq.com/wxpay/pay.php",
"goods_tag" : "WXG",
"support_fapiao" : true,
"amount" : {
"total" : 100,
"currency" : "CNY"
},
"payer" : {
"openid" : "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o\t"
},
"detail" : {
"cost_price" : 608800,
"invoice_id" : "微信123",
"goods_detail" : [
{
"merchant_goods_id" : "1246464644",
"wechatpay_goods_id" : "1001",
"goods_name" : "iPhoneX 256G",
"quantity" : 1,
"unit_price" : 528800
}
]
},
"scene_info" : {
"payer_client_ip" : "14.23.150.211",
"device_id" : "013467007045764",
"store_info" : {
"id" : "0001",
"name" : "腾讯大厦分店",
"area_code" : "440305",
"address" : "广东省深圳市南山区科技中一道10000号"
}
},
"settle_info" : {
"profit_sharing" : false
}
}'
应答参数:
200 OK
prepay_id必填string(64)
【预支付交易会话标识】 预支付交易会话标识。用于后续接口调用中使用,该值有效期为2小时
应答示例
{
"prepay_id" : "wx201410272009395522657a690389285100"
}
2.1 接口分析
参考api接口文档定义封装响应数据的实体类型WeChatPayVo,如下所示:
@Data // 请求微信JSAPI下单接口响应数据模型
@Schema(description = "支付下单响应数据模型")
public class WeChatPayVo {
@Schema(description = "时间戳")
private String timeStamp ; // 时间戳
@Schema(description = "随机字符串")
private String nonceStr ; // 随机字符串
@Schema(description = "订单详情扩展字符串")
@JsonProperty(value = "package")
private String packageVal ; // 订单详情扩展字符串
@Schema(description = "签名方式")
private String signType ; // 签名方式
@Schema(description = "签名")
private String paySign ; // 签名
}
在配置文件中配置微信支付相关参数
# 微信支付所需要的账号信息#
wechat.v3pay.appid=
# 商户号
wechat.v3pay.merchantId=
# 商户API私钥路径
wechat.v3pay.privateKeyPath=apiclient_key.pem
# 商户证书序列号
wechat.v3pay.merchantSerialNumber=
# 商户APIV3密钥
wechat.v3pay.apiV3key=
# 异步回调地址
wechat.v3pay.notifyUrl=http://127.0.0.1/api/payment/wxPay/notify
2.2 接口开发
编写一个微信支付接口
@Operation(summary = "微信下单")
@Parameters({
@Parameter(name = "paymentType",description = "支付类型:1301-订单 1302-充值",in = ParameterIn.PATH,required = true),
@Parameter(name = "orderNo",description = "订单号",required = true,in = ParameterIn.PATH),
})
@PostMapping("/createJsapi/{paymentType}/{orderNo}")
public Result<WeChatPayVo> createJsapi(@PathVariable String paymentType, @PathVariable String orderNo) {
WeChatPayVo weChatPayVo = wxPayService.createJsapi(paymentType, orderNo);
return Result.ok(weChatPayVo);
}
业务层代码: 在WxPayService接口中添加如下接口方法:
// WxPayService
public abstract WeChatPayVo createJsapi(String paymentType, String orderNo);
// WxPayServiceImpl
@Override
public WeChatPayVo createJsapi(String paymentType, String orderNo) {
try {
// 根据订单的编号查询订单数据(下面两行代码无需考虑,这里只是获取订单信息)
Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfo(orderNo);
OrderInfo orderInfo = orderInfoResult.getData();
// 可以提前保存交易信息
// paymentInfoService.savePaymentInfo(orderInfo);
// 构建service
JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
// 构建请求参数对象
PrepayRequest request = new PrepayRequest();
// 注意在这个包下 com.wechat.pay.java.service.payments.jsapi.model.Amount
Amount amount = new Amount();
amount.setTotal(1);
request.setAmount(amount);
request.setAppid(wxPayV3Config.getAppid());
request.setMchid(wxPayV3Config.getMerchantId());
request.setDescription(orderInfo.getOrderTitle()); // 订单标题
request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
request.setOutTradeNo(orderNo);
// 设置支付者
Result<UserInfo> userInfoResult = userInfoFeignClient.findByUserId(AuthContextHolder.getUserId());
UserInfo userInfo = userInfoResult.getData();
String wxOpenId = userInfo.getWxOpenId();
Payer payer = new Payer() ;
payer.setOpenid(wxOpenId);
request.setPayer(payer);
// response包含了调起支付所需的所有参数,可直接用于前端调起支付
PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
// 解析响应结果构建
WeChatPayVo weChatPayVo = new WeChatPayVo() ;
weChatPayVo.setTimeStamp(response.getTimeStamp());
weChatPayVo.setNonceStr(response.getNonceStr());
weChatPayVo.setPackageVal(response.getPackageVal());
weChatPayVo.setSignType(response.getSignType());
weChatPayVo.setPaySign(response.getPaySign());
// 返回数据
return weChatPayVo;
} catch (Exception e){
e.printStackTrace();
throw new GuiguException(201,"微信下单异常");
}
}
定义一个实体类封装微信支付所需要的参数, 并且在该实体类中配置RSAAutoCertificateConfig到spring容器中,代码如下所示:
@Configuration
@ConfigurationProperties(prefix="wechat.v3pay") //读取节点
@Data
public class WxPayV3Config {
private String appid;
public String merchantId; /** 商户号 */
public String privateKeyPath; /** 商户API私钥路径 */
public String merchantSerialNumber; /** 商户证书序列号 */
public String apiV3key; /** 商户APIV3密钥 */
private String notifyUrl; /** 回调地址 */
@Bean
public RSAAutoCertificateConfig autoCertificateConfig() {
RSAAutoCertificateConfig rsaAutoCertificateConfig = new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3key)
.build();
return rsaAutoCertificateConfig ;
}
}
3. 查询支付状态
微信支付订单号查询订单:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/query-by-wx-trade-no.html
微信支付工具类示例Demo:https://github.com/wechatpay-apiv3/wechatpay-java
3.1 接口开发
控制层代码:
在WxPayApiController中添加如下方法:
@Operation(summary = "支付状态查询")
@GetMapping("/queryPayStatus/{orderNo}")
public Result queryPayStatus(@PathVariable String orderNo) {
boolean result = wxPayService.queryPayStatus(orderNo);
return Result.ok(result);
}
业务层代码:
在WxPayService中添加如下业务接口方法
// WxPayService
public abstract boolean queryPayStatus(String orderNo);
// WxPayServiceImpl
@Override
public boolean queryPayStatus(String orderNo) {
try {
// 构建JsapiServiceExtension对象
JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
// 构建请求参数对象
QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
queryRequest.setMchid(wxPayV3Config.getMerchantId());
queryRequest.setOutTradeNo(orderNo);
// 发送查询请求
Transaction result = service.queryOrderByOutTradeNo(queryRequest);
// 更新支付信息数据的支付状态
if(result != null && result.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
paymentInfoService.updatePaymentStatus(result); //更改订单状态
return true ;
}
} catch (ServiceException e){ // API返回失败, 例如ORDER_NOT_EXISTS
log.error("code={}, message={}" , e.getErrorCode() , e.getErrorMessage());
log.error("reponse body={}" , e.getResponseBody());
e.printStackTrace();
return false ;
}
return false ;
}
支付成功后可以修改订单的支付状态!
4. 异步通知
微信支付通过支付通知接口将用户支付成功消息通知给商户。异步通知规则如下所示:
用户支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理该消息,并返回应答。
对后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。(通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m)
支付通知API官网地址:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/payment-notice.html
API字典官网地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_5.shtml
上述的两个地址都可以查询对应的接口文档,但是存在差异化,建议以第二个地址为准。
支付通知示例代码地址:https://github.com/wechatpay-apiv3/wechatpay-java
4.1 接口开发
表现层代码
在WxPayApiController中添加如下的接口方法
// WxPayApiController
@Operation(summary = "微信支付异步通知接口")
@PostMapping("/notify")
public ResponseEntity<Map<String , String>> notify(HttpServletRequest request){
Map<String , String> result = new HashMap<>() ;
try {
wxPayService.wxnotify(request);
result.put("code" , "SUCCESS") ;
result.put("message" , "成功") ;
return ResponseEntity.status(HttpStatus.OK).body(result);
}catch (Exception e) {
e.printStackTrace();
result.put("code" , "FAIL") ;
result.put("message" , "失败") ;
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result) ;
}
}
业务层代码
参考支付通知示例代码,在WxPayService中添加如下的接口方法
// WxPayService
public abstract void wxnotify(HttpServletRequest request);
// WxPayServiceImpl
@Override
public void wxnotify(HttpServletRequest request) {
// 获取请求参数
String wechatPaySerial = request.getHeader("Wechatpay-Serial");
String nonce = request.getHeader("Wechatpay-Nonce");
String timestamp = request.getHeader("Wechatpay-Timestamp");
String signature = request.getHeader("Wechatpay-Signature");
// HTTP请求体 body。切记使用原始报文,不要用JSON对象序列化后的字符串,避免验签的body和原文不一致。
String requestBody = PayUtil.readData(request);
// 构造 RequestParam
RequestParam requestParam = new RequestParam.Builder()
.serialNumber(wechatPaySerial)
.nonce(nonce)
.signature(signature)
.timestamp(timestamp)
.body(requestBody)
.build();
// 初始化 NotificationParser
NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
// 解析请求参数得到Transaction对象
Transaction result = parser.parse(requestParam, Transaction.class);
// 更新支付信息数据的支付状态
if(result != null && result.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
paymentInfoService.updatePaymentStatus(result); //更改订单状态
}
}
标签:String,商户,接入,微信,request,接口,支付
From: https://www.cnblogs.com/lilyflower/p/18457825