微信支付接口接入

微信支付接口接入

微信支付接口接入

微信支付接入文档参考(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 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 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 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> notify(HttpServletRequest request){

Map 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); //更改订单状态

}

}

相关文章

365bet亚洲真人 excel销售人员业绩表怎么做

excel销售人员业绩表怎么做

🗓️ 09-18 👁️ 1368
365bet亚洲真人 秀色秀场电脑网页版(秀色秀丽)

秀色秀场电脑网页版(秀色秀丽)

🗓️ 07-05 👁️ 5787
365500 美俏画眉神器对比测评:粘贴式眉卡与其他眉粉套装的优劣分析
beat365倍率 菜鸟也上手:最最完整的Cool Edit Pro 图文操作手册
365bet亚洲真人 自拍依旧出色,其他有待进步:美图M8体验
365bet亚洲真人 dnf刺客传说耳环哪个好

dnf刺客传说耳环哪个好

🗓️ 09-21 👁️ 2511