2025版微信商家转账API V3 JAVA完整源码零障碍对接指南
前言
- 本教程操作简便,提供完整源码。
- 本文主要阐述java后端的对接流程,包含功能开启以及前端调用相关内容。基础版无需提交资料审核,但额度仅有200,具体可参考官方文档产品介绍_商家转账|微信支付商户文档中心。
- 自去年年末起,原微信商家转账到零钱功能停止开放,替换为商家转账功能。与以往的商家转账到零钱相比,新流程多了用户确认步骤,通过API发起转账后,还需用户在商户小程序中点击确认(前端指引->JSAPI调起用户确认收款_商家转账|微信支付商户文档中心)。
一、引入微信支付官方SDK
无需自行开发,直接引入微信支付官方提供的SDK,相关依赖如下:
<!-- 微信支付sdk -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.15</version>
</dependency>
二、封装实体类
后端API包含发起转账、查询转账、撤销转账三个方法,且状态变更有异步回调通知,因此封装如下实体类(请勿修改@serializedName
注解)。
1. 请求实体类(仅发起转账需要封装,其他接口通过路径传参)
/**
* 发起商家转账参数
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TransferCreateRequest {
@SerializedName("appid")
private String appid;
@SerializedName("out_bill_no")
private String outBillNo;
@SerializedName("transfer_scene_id")
private String transferSceneId;
@SerializedName("openid")
private String openid;
@SerializedName("user_name")
private String userName;
@SerializedName("transfer_remark")
private String transferRemark;
@SerializedName("transfer_amount")
private Integer transferAmount;
@SerializedName("notify_url")
private String notifyUrl;
/**
* 【用户收款感知】
* 用户收款时感知到的收款原因将根据转账场景自动展示默认内容。
* 如有其他展示需求,可在本字段传入。
* 各场景展示的默认内容和支持传入的内容,可查看产品文档了解。
*/
@SerializedName("user_recv_perception")
private String userRecvPerception;
/**
* 【转账场景报备信息】 各转账场景下需报备的内容,商户需要按照所属转账场景规则传参,详见转账场景报备信息字段说明。
*/
@SerializedName("transfer_scene_report_infos")
private List<TransferSceneReportInfo> transferSceneReportInfos;
@Override
public String toString() {
return GsonUtil.getGson().toJson(this);
}
}
/**
* 转账场景报备信息
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TransferSceneReportInfo {
/**
* 【信息类型】 不能超过15个字符,商户所属转账场景下的信息类型,此字段内容为固定值,需严格按照转账场景报备信息字段说明传参。
*/
@SerializedName("info_type")
private String infoType;
/**
* 【信息内容】 不能超过32个字符,商户所属转账场景下的信息内容,商户可按实际业务场景自定义传参,需严格按照转账场景报备信息字段说明传参。
*/
@SerializedName("info_content")
private String infoContent;
@Override
public String toString() {
return GsonUtil.getGson().toJson(this);
}
}
2. 响应实体类
@Data
public class TransferCreateResponse {
@SerializedName("transfer_bill_no")
private String transferBillNo;
@SerializedName("out_bill_no")
private String outBillNo;
@SerializedName("create_time")
private Date createTime;
/**
* 【单据状态】 商家转账订单状态
* 可选取值
* ACCEPTED: 转账已受理
* PROCESSING: 转账锁定资金中。如果一直停留在该状态,建议检查账户余额是否足够,如余额不足,可充值后再原单重试。
* WAIT_USER_CONFIRM: 待收款用户确认,可拉起微信收款确认页面进行收款确认
* TRANSFERING: 转账中,可拉起微信收款确认页面再次重试确认收款
* SUCCESS: 转账成功
* FAIL: 转账失败
* CANCELING: 商户撤销请求受理成功,该笔转账正在撤销中
* CANCELLED: 转账撤销完成
*/
@SerializedName("state")
private String state;
/**
* 【失败原因】 订单已失败或者已退资金时,会返回订单失败原因
* <a href="https://pay.weixin.qq.com/doc/v3/merchant/4013774966">...</a>
*/
@SerializedName("fail_reason")
private String failReason;
/**
* 【跳转领取页面的package信息】 跳转微信支付收款页的package信息,APP调起用户确认收款或者JSAPI调起用户确认收款 时需要使用的参数。
* 单据创建后,用户24小时内不领取将过期关闭,建议拉起用户确认收款页面前,先查单据状态:如单据状态为待收款用户确认,可用之前的package信息拉起;单据到终态时需更换单号重新发起转账。
*/
@SerializedName("package_info")
private String packageInfo;
}
@Data
public class TransferQueryResponse {
@SerializedName("mch_id")
private String mchid;
@SerializedName("transfer_bill_no")
private String transferBillNo;
@SerializedName("out_bill_no")
private String outBillNo;
@SerializedName("appid")
private String appid;
/**
* 【单据状态】 商家转账订单状态
* 可选取值
* ACCEPTED: 转账已受理
* PROCESSING: 转账锁定资金中。如果一直停留在该状态,建议检查账户余额是否足够,如余额不足,可充值后再原单重试。
* WAIT_USER_CONFIRM: 待收款用户确认,可拉起微信收款确认页面进行收款确认
* TRANSFERING: 转账中,可拉起微信收款确认页面再次重试确认收款
* SUCCESS: 转账成功
* FAIL: 转账失败
* CANCELING: 商户撤销请求受理成功,该笔转账正在撤销中
* CANCELLED: 转账撤销完成
*/
@SerializedName("state")
private String state;
@SerializedName("transfer_amount")
private Integer transferAmount;
@SerializedName("transfer_remark")
private String transferRemark;
@SerializedName("fail_reason")
private String failReason;
@SerializedName("openid")
private String openid;
@SerializedName("user_name")
private String userName;
/**
* 【单据创建时间】遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,
* yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,
* TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
* 例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
*/
@SerializedName("create_time")
private Date createTime;
/**
* 【最后一次状态变更时间】遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,
* yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,
* TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
* 例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
*/
@SerializedName("update_time")
private Date updateTime;
}
@Data
public class TransferCancelResponse {
/**
* 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
*/
@SerializedName("out_bill_no")
private String outBillNo;
/**
* 商家转账订单的主键,唯一定义此资源的标识
*/
@SerializedName("transfer_bill_no")
private String transferBillNo;
/**
* 【单据状态】 CANCELING: 撤销中;CANCELLED:已撤销
*/
@SerializedName("state")
private String state;
/**
* 【最后一次单据状态变更时间】 按照使用rfc3339所定义的格式,格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
*/
@SerializedName("update_time")
private Date updateTime;
}
3. 异步回调参数
@Data
public class TransferNotification {
@SerializedName("transfer_bill_no")
private String transferBillNo;
@SerializedName("out_bill_no")
private String outBillNo;
/**
* 【单据状态】 商家转账订单状态
* 可选取值
* ACCEPTED: 转账已受理
* PROCESSING: 转账锁定资金中。如果一直停留在该状态,建议检查账户余额是否足够,如余额不足,可充值后再原单重试。
* WAIT_USER_CONFIRM: 待收款用户确认,可拉起微信收款确认页面进行收款确认
* TRANSFERING: 转账中,可拉起微信收款确认页面再次重试确认收款
* SUCCESS: 转账成功
* FAIL: 转账失败
* CANCELING: 商户撤销请求受理成功,该笔转账正在撤销中
* CANCELLED: 转账撤销完成
*/
@SerializedName("state")
private String state;
@SerializedName("mch_id")
private String mchId;
@SerializedName("transfer_amount")
private Integer transferAmount;
@SerializedName("openid")
private String openid;
/**
* 【失败原因】 订单已失败或者已退资金时,会返回订单失败原因
* <a href="https://pay.weixin.qq.com/doc/v3/merchant/4013774966">...</a>
*/
@SerializedName("fail_reason")
private String failReason;
/**
* 【单据创建时间】遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,
* yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,
* TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
* 例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
*/
@SerializedName("create_time")
private Date createTime;
/**
* 【最后一次状态变更时间】遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,
* yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,
* TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
* 例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
*/
@SerializedName("update_time")
private Date updateTime;
}
三、封装service
对于只兼容商家转账且单商户配置的情况,可在service上添加@component
注解,在构造方法中使用@autowired
实现单例模式(官方推荐),示例代码如下:
public class TransferNewService {
private final HttpClient httpClient;
private final PrivacyEncryptor encryptor;
private final PrivacyDecryptor decryptor;
/**
* 实际注入实体类为 RSAAutoCertificateConfig
* @param config 不要引用错了 包路径 com.wechat.pay.java.core.Config;
*/
public TransferNewService(Config config) {
this.httpClient =
new DefaultHttpClientBuilder()
.credential(requireNonNull(config.createCredential()))
.validator(requireNonNull(config.createValidator()))
.build();
this.encryptor = config.createEncryptor();
this.decryptor = config.createDecryptor();
}
/**
* 创建商家转账订单
* @param request 请求参数
* @return 响应参数
*/
public TransferCreateResponse createTransferOrder(TransferCreateRequest request) {
String requestPath = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills";
Objects.requireNonNull(this.encryptor);
request.setUserName(this.encryptor.encrypt(request.getUserName()));
return executeHttpRequest(requestPath,HttpMethod.POST,request.toString(),TransferCreateResponse.class);
}
/**
* 撤销商家转账订单
* 商户通过转账接口发起付款后,在用户确认收款之前可以通过该接口撤销付款。
* 该接口返回成功仅表示撤销请求已受理,
* 系统会异步处理退款等操作,
* 以最终查询单据返回状态为准。
* @param outBillNo 商户转账单号
* @return 响应参数
*/
public TransferCancelResponse cancelTransferOrder(String outBillNo){
String requestPath =
"https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/{out_bill_no}/cancel";
requestPath =
requestPath.replace("{" + "out_bill_no" + "}", outBillNo);
return executeHttpRequest(requestPath,HttpMethod.POST,null,TransferCancelResponse.class);
}
public TransferQueryResponse queryTransferByOutBillNo(String outBillNo){
String requestPath =
"https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/{out_bill_no}";
requestPath =
requestPath.replace("{" + "out_bill_no" + "}", outBillNo);
TransferQueryResponse response = executeHttpRequest(requestPath, HttpMethod.GET, null, TransferQueryResponse.class);
response.setUserName(decryptor.decrypt(response.getUserName()));
return response;
}
public TransferQueryResponse queryTransferByTransferBillNo(String transferBillNo){
String requestPath =
"https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/{transfer_bill_no}";
requestPath =
requestPath.replace("{" + "transfer_bill_no" + "}", transferBillNo);
TransferQueryResponse response = executeHttpRequest(requestPath, HttpMethod.GET, null, TransferQueryResponse.class);
response.setUserName(decryptor.decrypt(response.getUserName()));
return response;
}
public <T> T executeHttpRequest(String requestPath,HttpMethod method,String body,Class<T> responseClass){
HttpHeaders headers = new HttpHeaders();
headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
HttpRequest httpRequest =
new HttpRequest.Builder()
.httpMethod(method)
.url(requestPath)
.headers(headers)
.body(StringUtils.hasText(body)?new JsonRequestBody.Builder().body(body).build():null)
.build();
HttpResponse<T> httpResponse =
httpClient.execute(httpRequest, responseClass);
return httpResponse.getServiceResponse();
}
}
四、配置注入
单商户模式只需完成Config配置类注册即可调用。非常关键****若为24年11月以后注册的商户,需检查商户后台配置,有兄弟在评论区提到平台证书模式可能新商户不支持。进入账户中心->API安全,根据自己的商户号证书类型,
相关文章
暂无评论...