1.背景说明
     2.实现过程
         2.1 接入之前的准备工作
         2.2 代码实现
     3.注意事项以及相关说明
         3.1 参数组装说明
         3.2 resource配置文件读取
         3.3 错误的签名,验签失败问题分析以及处理
         3.4.转账到零钱产品功能配置
         3.5.linux环境部署jar:cannot be resolved to absolute file path because it does not reside in the file system问题处理
         3.6.转账到零钱接口返回API通道未开启问题处理
         3.7.转账到零钱免密额度开启功能使用说明
         3.8.关于如何判断零钱是否到账的说明

背景说明

近期营销活动中需要商户转账到微信用户零钱,实战角度说下接入过程,期间用的时间也比较多,把遇到的问题以及如何处理问题过程记录一下,希望对有同样需求的同学有所帮助,尽量少用一些时间,更专注业务处理.本文仅以发起商家转账( /v3/transfer/batches)功能进行讲解.

2.实现过程

2.1接入之前的准备工作

开通微信商户账号以及开通商家转账到零钱产品功能并对指定功能进行相关设置.官方接入的详情地址:
https://pay.weixin.qq.com/docs/merchant/products/batch-transfer-to-balance/preparation.html

2.2 代码实现

controller:

 @ApiOperation("提现到零钱")@PostMapping("/transferAccount")public ResultVo transferAccount(String openId) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, IOException, KeyStoreException {payService.transferAccount(openId);return ResultVoUtil.success();}

service:

public interface PayService {// add by txm 2022/10/29 提现到微信零钱void transferAccount(String openIdId) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException, KeyStoreException;}

参数实体类:

@ApiModel("转账请求参数")
@Data
public class TransferDto  {@ApiModelProperty(value = "直连商户的appid",example = "123",dataType = "String")private String appid;@ApiModelProperty(value = "商家批次单号",example = "plfk2020042013",dataType = "String")private String out_batch_no;@ApiModelProperty(value = "批次名称",example = "2019年1月深圳分部报销单",dataType = "String")private String batch_name;@ApiModelProperty(value = "批次备注",example = "2019年1月深圳分部报销单",dataType = "String")private String batch_remark;@ApiModelProperty(value = "转账总金额,单位分",example = "1",dataType = "Integer")private Integer total_amount;@ApiModelProperty(value = "转账总笔数",example = "1",dataType = "Integer")private Integer total_num;@ApiModelProperty(value = "转账明细列表",dataType = "list.class")private List<TransferDetailDto> transfer_detail_list=new ArrayList<>();
}
@ApiModel("转账请求详情参数")
@Data
public class TransferDetailDto  {@ApiModelProperty(value = "商家明细单号(相当于子订单)",example = "x23zy545Bd5436",dataType = "String")private String out_detail_no;@ApiModelProperty(value = "转账金额,单位分",example = "2",dataType = "Integer")private Integer transfer_amount;@ApiModelProperty(value = "转账备注",example = "2020年4月报销",dataType = "String")private String transfer_remark;@ApiModelProperty(value = "用户在直连商户应用下的用户标示",example = "2019年1月深圳分部报销单",dataType = "String")private String openid;}

业务实现类:

@Slf4j
@Service
public class PayServiceImpl implements PayService {/*** @Author: txm* @Description: 转账逻辑* @Param: [method, url, body]* @return: java.lang.String* @Date:  2022/11/24 16:08**/@Overridepublic void transferAccount(String openIdId) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException, KeyStoreException {// 组装转账到零钱参数TransferDto transferDto = new TransferDto();transferDto.setAppid("小程序APPID或是公众号id");String out_batch_no = RandomUtil.randomNumbers(10);out_batch_no=StrUtil.concat(true,"sc",out_batch_no);transferDto.setOut_batch_no(out_batch_no);transferDto.setBatch_name("test1");transferDto.setBatch_remark("test2");transferDto.setTotal_amount(1);transferDto.setTotal_num(1);TransferDetailDto transferDetailDto = new TransferDetailDto();String out_detail_no = RandomUtil.randomNumbers(10);out_detail_no=StrUtil.concat(true,"detail",out_detail_no);transferDetailDto.setOut_detail_no(out_detail_no);transferDetailDto.setTransfer_amount(1);transferDetailDto.setTransfer_remark("test3");transferDetailDto.setOpenid(openIdId);transferDto.getTransfer_detail_list().add(transferDetailDto);String transferDtoStr = JSONUtil.toJsonStr(transferDto);// 组装Authorization信息HttpUrl httpUrl = HttpUrl.get("https://api.mch.weixin.qq.com/v3/transfer/batches");String tokenInfo=getToken("POST",httpUrl,transferDtoStr);log.info("Authorization认证信息:{}",tokenInfo);// Authorization认证类型String authType="WECHATPAY2-SHA256-RSA2048";// Authorization信息 认证类型 认证信息,此处使用hutool工具类中concat进行拼接,注意两部分中间用空格分割String authorization= StrUtil.concat(true, authType," ",tokenInfo);// 发送请求String returnMsg = HttpRequest.post("https://api.mch.weixin.qq.com/v3/transfer/batches").header("Authorization", authorization).header("Wechatpay-Serial","证书序列号").body(transferDtoStr).execute().body();JSONObject returnTransferInfo = JSON.parseObject(returnMsg);log.info("转账申请返回信息:{}",returnTransferInfo);}/*** @Author: txm* @Description: 获取Authorization认证签名信息* @Param: [method, url, body]* @return: java.lang.String* @Date:  2022/11/24 16:08**/public  String getToken(String method, HttpUrl url, String body) throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, KeyStoreException {// 随机字符串String nonceStr = RandomUtil.randomString(26);// 时间戳,单位秒long timestamp = System.currentTimeMillis() / 1000;// 组装签名串信息String message = buildMessage(method, url, timestamp, nonceStr, body);log.info("签名串:{}",message);// 签名串加密处理String signature = sign(message.getBytes("utf-8"));log.info("签名信息:{}",signature);return "mchid=\"" + "商户id" + "\","+ "serial_no=\"" + "证书序列号" + "\","+ "nonce_str=\"" + nonceStr + "\","+ "timestamp=\"" + timestamp + "\","+ "signature=\"" + signature + "\"";}/*** @Author: txm* @Description: 组装签名请求信息* @Param: [method, url, timestamp, nonceStr, body]* @return: java.lang.String* @Date:  2022/11/24 16:09**/public String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {String canonicalUrl = url.encodedPath();if (url.encodedQuery() != null) {canonicalUrl += "?" + url.encodedQuery();}return method + "\n"+ canonicalUrl + "\n"+ timestamp + "\n"+ nonceStr + "\n"+ body + "\n";}/*** @Author: txm* @Description: 签名加密* @Param: [byte[]]* @return: java.lang.String* @Date:  2022/11/24 16:09**/public String sign(byte[] message) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, KeyStoreException, IOException {Signature sign = Signature.getInstance("SHA256withRSA");// apiclient_key.pem存在到resource/config/cert下Resource resource = resourceLoader.getResource("classpath:/config/cert/apiclient_key.pem");File file = resource.getFile();String path = file.getPath();// 获取私钥key,实际读取apiclient_key.pem文件信息创建PrivateKey 对象PrivateKey privateKey = getPrivateKey(path);sign.initSign(privateKey);sign.update(message);return Base64.encodeBase64String(sign.sign());}/*** @Author: txm* @Description: 获取PrivateKey * @Param: [byte[]]* @return: java.lang.String* @Date:  2022/11/24 16:09**/public static PrivateKey getPrivateKey(String filename) throws IOException {String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");try {String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");KeyFactory kf = KeyFactory.getInstance("RSA");return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)));} catch (NoSuchAlgorithmException e) {throw new RuntimeException("当前Java环境不支持RSA", e);} catch (InvalidKeySpecException e) {throw new RuntimeException("无效的密钥格式");}}}

3.注意事项以及相关说明

3.1 参数组装说明

3.1参数组装说明
    转账到微信零钱官方文档:https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-batch/initiate-batch-transfer.html
    请求由两部分组成:详细请求信息和请求头信息,前者不用多说,按照官方文档进行参数对应即可.后者请求头信息包含两个请求头:Wechatpay-SerialAuthorization,前者为证书序列号,可以直接从商户平台证书管理中查看,Authorization为签名信息.

签名解释的稍微通俗一点,就是把要传递给接口的参数,进行加密,加密的这个动作就是签名,作用就是保障这条请求是你的请求是安全的.

Authorization又分为两部分:认证类型(固定为WECHATPAY2-SHA256-RSA2048)和认证信息.认证信息由商户号、随机字符串、时间戳(单位秒)、证书序列号、签名信息组成,其中签名信息由请求方式、随机字符串、时间戳(单位秒)、请求路径(/v3/transfer/batches)、请求体加密组成.具体以官方文档为准.参数确实很多,不过代码里面都已经组装好了,只需要更换对应的配置信息即可.接入过程中会遇到很多问题,自己已经调通,很多坑已经踩过,按照上面的签名方式进行可以排除掉大部分可能出现错误原因.

3.2.resource配置文件读取

首先说下和证书相关的三个文件:
apiclient_cert.p12 商户证书,
apiclient_cert.pem 商户证书相关加密文件,
apiclient_key.pem 商户秘钥文件.后两者都是基于证书进行导出的.基本上都是商户证书用的多比如说支付或是退款,后两者用的不多。其中获取privateKey对象就是基于读取apiclient_key.pem实现.在springboot项目中配置文件一般放置在resource目录下,关于读取方式这里踩过坑,可以使用resourceLoader进行读取.具体实现参考上面代码.

3.3 错误的签名,验签失败问题分析以及处理

接口本地测试的时候这个问题耗费的时间最多,也是大部分同学都会遇到的问题,看过一篇总结贴感觉不错,可以按照里面说的进行自查:验签失败原因分析.
仔细对比之后验签失败的原因锁定在商户号、证书序列号、apiclient_key.pem三者是否匹配这个问题上。关于校验三者是否匹配,提供的检验方法是使用postman导入官方提供的测试脚本,具体操作可以参考:
https://github.com/wechatpay-apiv3/wechatpay-postman-script
按照步骤执行之后发现测试结果是认证失败,所以考虑如何将三者进行正确匹配。
    简单交代下我的情况:apiclient_cert.p12apiclient_key.pem都是之前的人交接过来的,由于线上支付和退款都正常在用,所以apiclient_cert.p12 证书序列号 商户号应该是正常的,那唯一有问题的可能就是apiclient_key.pem.apiclient_key.pem可以通过apiclient_cert.p12重新导出,毕竟如果更换apiclient_cert.p12 需要将线上的证书进行更换,成本较大.
    使用apiclient_cert.p12生成apiclient_key.pem的方法是使用openssl.
window 64位openssl下载地址后期补充.
安装直接默认安装即可,不再展开.
    安装好之后打开黑窗口,进入到apiclient_cert.p12所在目录(可以将原来的apiclient_key.pem重命名做备份),运行以下命令即可生成apiclient_key.pem:

openssl pkcs12 -nodes -clcerts -in apiclient_cert.p12 -out apiclient_key.pem

如果提示输入密码,可以直接输入商户号.生成的文件中保留从-----BEGIN PRIVATE KEY-----到-----END PRIVATE KEY----内容即可,否则解析文件时会失败.生成新的apiclient_key.pem重新请求接口签名问题解决.
    这里说下之前感到困惑的地方,官方提供过签名以及验签的工具,注意工具只校验签名的方式是否正确,不校验参数的正确性.问题记录贴:
https://developers.weixin.qq.com/community/pay/doc/00004e6fa08528c447eea27cf56800

3.4.转账到零钱产品功能配置

商户平台开通转账到零钱产品只是第一步,需要到产品设置中进行开启api权限相关配置,设置比较简单这里不在展开.可能会出现问题的步骤下文会有记录,继续往下看.

3.5.linux环境部署jar:cannot be resolved to absolute file path because it does not reside in the file system问题处理

本地自测时一切正常,但是打包部署到线上之后接口异常,异常信息如下:

cannot be resolved to absolute file path because it does not reside in the file system

出现这个问题的原因是spring中不能通过file方式读取jar中内容信息.可以使用inputStream的方式进行读取.
涉及修改的是sign方法:

 public String sign(byte[] message) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, KeyStoreException, IOException {Signature sign = Signature.getInstance("SHA256withRSA");// 存在问题: class path resource [config/cert/apiclient_key.pem] cannot be resolved to absolute file path because it does not reside in the file system:// 原因:打包之后,spring没办法通过File的形式访问jar包里面的文件。/*  Resource resource = resourceLoader.getResource('classpath:/config/cert/apiclient_key.pem');File file = resource.getFile();String path = file.getPath();PrivateKey privateKey = getPrivateKey(path);*/Resource resource = resourceLoader.getResource("classpath:/config/cert/apiclient_key.pem");PrivateKey privateKey = PemUtil.loadPrivateKey(resource.getInputStream());sign.initSign(privateKey);sign.update(message);return Base64.encodeBase64String(sign.sign());}

添加PemUtil.java

public class PemUtil {public static PrivateKey loadPrivateKey(String privateKey) {privateKey = privateKey.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");try {KeyFactory kf = KeyFactory.getInstance("RSA");return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));} catch (NoSuchAlgorithmException e) {throw new RuntimeException("当前Java环境不支持RSA", e);} catch (InvalidKeySpecException e) {throw new RuntimeException("无效的密钥格式");}}public static PrivateKey loadPrivateKey(InputStream inputStream) {ByteArrayOutputStream os = new ByteArrayOutputStream(2048);byte[] buffer = new byte[1024];String privateKey;try {for (int length; (length = inputStream.read(buffer)) != -1; ) {os.write(buffer, 0, length);}privateKey = os.toString("UTF-8");} catch (IOException e) {throw new IllegalArgumentException("无效的密钥", e);}return loadPrivateKey(privateKey);}public static X509Certificate loadCertificate(InputStream inputStream) {try {CertificateFactory cf = CertificateFactory.getInstance("X509");X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);cert.checkValidity();return cert;} catch (CertificateExpiredException e) {throw new RuntimeException("证书已过期", e);} catch (CertificateNotYetValidException e) {throw new RuntimeException("证书尚未生效", e);} catch (CertificateException e) {throw new RuntimeException("无效的证书", e);}}
}

修改之后重新上线问题处理.

3.6.转账到零钱接口返回API通道未开启问题处理

转账申请接口验签调通之后,可能会遇到API通道未开启的错误提示,原因是没有开启API发起功能,点击前往功能按钮,如果是未设置任何发起方式会提醒开通下面哪种发起方式,接口申请选择API发起转账.



开启需要设置服务端的ip地址(注意本机ip无效,另外配置完成之后可能会有延迟).


添加允许访问ip之后需要设置转账验密人,这个转账验密人的意思就是每发起一笔转账申请,验密人微信客户端会收到转账提醒消息,需要输入转账设置的密码和接收到的短信验证码方可转账成功.

转账成功之后的到账截图:

到这里基本发起转账申请以及零钱到账功能基本已经打通,

3.7.转账到零钱免密额度开启功能使用说明

每笔转账申请需要验密人进行密码和短信验证码校验.很不方便,如何不进行验密人同意直接转正到零钱呢,对应的设置就是免密额度功能开启,只要在设置好的免密额度之内的转账申请不需要验密人同意即可到账零钱.
   开启免密额度功能需要先设置允许的免密额度

   然后开启安全医生功能,这里需要添加诊断链接,就是验证域名是否合法.


   添加诊断链接步骤如下:

   这里说明一下下载的验证文件放置位置,文档中说的是放置于配置域名的根目录.说下自己的项目部署结构,项目访问域名:https://A.com/distributionDev/
前端项目部署在nginx,后端springboot项目访问地址:https://A.com:8083.
测试页面verify_4658330f30affb076ec2f21940d4e4e8.html两种放置方式
   放置于前端项目下:
   访问链接:https://A.com/distributionDev/verify_4658330f30affb076ec2f21940d4e4e8.html
   放置于服务端项目下:

   访问链接(同添加的诊断链接):https://A.com:8083/verify_4658330f30affb076ec2f21940d4e4e8.html.这里官方给出的说明可能有所歧义(官方给出诊断链接路径不用访问到测试页面),按照https://A.com:8083/verify_4658330f30affb076ec2f21940d4e4e8.html添加时验证通过,仅填写https://A.com:8083提示:您绑定的诊断链接格式有误,请检查后重试!
   关于服务端如何访问静态文件参考下文进行设置:
springboot项目URL访问Linux上的指定文件夹的静态资源文件以及访问本地任意磁盘文件设置
   与微信商户平台技术支持确认过,此处按照服务端配置测试页面的方式进行验证即可.安全医生功能开启之后免密功能开启!

3.8.关于如何判断零钱是否到账的说明

转账申请提交成功之后如何判断前是否到账到零钱?仔细看转账申请到零钱接口就会发现,官方给的申请成功的接口是没有状态码的(怎么不得返回一个类似200的状态码),但是给出了一堆异常的错误码,是不是感觉有些奇怪?已经和官方技术支持确认过,没错就是这么规定的.可以根据out_batch_no或是batch_id返回参数是否为空作为判断转账申请是否成功的依据.转账申请成功并不代表零钱到账成功,需要调用官方提供接口查询零钱到账详情判断是否到账,不过一般申请到账成功零钱就会到账,严谨起见,还是调用官方接口查询一下.提供了两种账单明细查询,这里选择第二种.

官方文档地址:https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-batch/get-transfer-batch-by-out-no.html
请求方式和转账申请方式差不多,这里直接贴一下代码:
controller:

 @ApiOperation(value = "查询转账到零钱账单详情信息",notes = "转账申请接口请求完成之后调用,以此判断是否到账用户,接口如果正常返回说明支付成功")@PostMapping("/findTransferDetail")public ResultVo findTransferDetail(@RequestBody @Validated TransferDetailQueryDto transferDetailQueryDto) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, IOException, KeyStoreException {payService.findTransferDetail(transferDetailQueryDto);return ResultVoUtil.success();}

请求参数:

@ApiModel("账单明细查询请求参数")
@Data
public class TransferDetailQueryDto implements Serializable {private static final long serialVersionUID = 8912898195432388263L;@ApiModelProperty(value = "商户系统内部区分转账批次单下不同转账明细单的唯一标识",example = "x23zy545Bd5436",dataType = "String")@NotBlank(message = "商户系统内部区分转账批次单下不同转账明细单不能为空!")private String out_batch_no;@ApiModelProperty(value = "商户系统内部的商家批次单号,在商户系统内部唯一",example = "2",dataType = "Integer")@NotBlank(message = "商户系统内部的商家批次单号不能为空!")private String out_detail_no;
}

实现类:

@Overridepublic void findTransferDetail(TransferDetailQueryDto transferDetailQueryDto) throws SignatureException, NoSuchAlgorithmException, KeyStoreException, InvalidKeyException, IOException {// 组装请求String requestUrl = StrUtil.concat(true, "https://api.mch.weixin.qq.com/v3/transfer/batches","/out-batch-no/", transferDetailQueryDto.getOut_batch_no(),"/details/out-detail-no/", transferDetailQueryDto.getOut_detail_no());// 组装authorizationString authorization = buildAuthorization("","GET",requestUrl);// 发送请求String returnMsg = HttpRequest.get(requestUrl).header("Authorization", authorization).execute().body();if(StrUtil.isBlank(returnMsg)) throw new BussinessExcption("查询转账详情信息失败:获取信息为空!");JSONObject returnTransferDetail = JSON.parseObject(returnMsg);// 处理响应String detail_status = returnTransferDetail.getString("detail_status");if(!"SUCCESS".equals(detail_status)) {log.error("转账详情返回信息:{}",returnTransferDetail);throw new BussinessExcption("转账失败:请联系工作人员!");}}/*** @Author: txm* @Description:* @Param: transferDtoStr:请求内容* @Param: method:请求方法* @Param: reqUrl:请求完整路径* @return: java.lang.String* @Date:  2022/12/1 11:54**/private String buildAuthorization(String transferDtoStr,String method,String reqUrl) throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, KeyStoreException {// 签名信息HttpUrl httpUrl = HttpUrl.get(reqUrl);String tokenInfo=getToken(method,httpUrl,transferDtoStr);log.info("Authorization认证信息:{}",tokenInfo);String authType="WECHATPAY2-SHA256-RSA2048";// 认证头信息return StrUtil.concat(true, authType," ",tokenInfo);}/*** @Author: txm* @Description: 获取签名信息* @Param: [method, url, body]* @return: java.lang.String* @Date:  2022/11/24 16:08**/public  String getToken(String method, HttpUrl url, String body) throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, KeyStoreException {String nonceStr = RandomUtil.randomString(26);long timestamp = System.currentTimeMillis() / 1000;String message = buildMessage(method, url, timestamp, nonceStr, body);log.info("签名串:{}",message);String signature = sign(message.getBytes("utf-8"));log.info("签名信息:{}",signature);return "mchid=\"" + "商户号" + "\","+ "serial_no=\"" + "证书序列号" + "\","+ "nonce_str=\"" + nonceStr + "\","+ "timestamp=\"" + timestamp + "\","+ "signature=\"" + signature + "\"";}/*** @Author: txm* @Description: 组装签名请求信息* @Param: [method, url, timestamp, nonceStr, body]* @return: java.lang.String* @Date:  2022/11/24 16:09**/public String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {String canonicalUrl = url.encodedPath();if (url.encodedQuery() != null) {canonicalUrl += "?" + url.encodedQuery();}return method + "\n"+ canonicalUrl + "\n"+ timestamp + "\n"+ nonceStr + "\n"+ body + "\n";}

根据detail_status状态是否为SUCCESS判断零钱是否到账.
    以上是对接商户转账到零钱过程中的总结和相关注意事项说明,看到这里希望对你有所帮助,欢迎评论区留言交流遇到的问题.

微信商户平台转账到零钱功能接入实战相关推荐

  1. 微信“商家转账到零钱“功能接入以及如何获得转账结果?

    先说答案:无法即时获得转账结果 首先按照商家转账到零钱文档接入,发现响应结果中没有转账成功或者失败的结果 使用通过微信批次单号查询批次单和通过微信明细单号查询明细单接口进行转账结果查询,发现无法即时获 ...

  2. 平台资金提现解决方案之实现微信商家转账到零钱功能

    大家好,我是小悟 使用场景 不管是做APP.电脑网站.手机网站还是小程序,为了推广基本上都离不开用户分佣的场景. 换句话说就是在其平台内为每个用户设置"电子钱包"功能,而电子钱包在 ...

  3. PHP微信支付 “商家转账到零钱”一文概述

    PHP微信支付 商家转账到零钱 这里有个坑 1:转账低于5毛会失败 2:转账金额需要自己取整一下,微信官方金额是 分 为单位,换算成 元 时可能会除不尽 { "code":&quo ...

  4. 微信商户平台注册步骤

    微信商户平台注册地址:注册地址 点击 "注册地址" 进入网页找到 "成为商家". 选择第一个"注册微信支付商户号" ,再使用注册人微信扫码: ...

  5. 微信公众平台推数据统计功能 商业价值可量化

    8月29日晚,微信产品团队通过服务号"微信公众平台"发布消息,宣布"微信公众平台增加数据统计功能".与此同时,细心的用户发现登陆微信公众平台,后台界面上增加了& ...

  6. java 朋友圈分享接口_Java实现微信公众平台朋友圈分享功能详细代码

    其实分享的方法在微信官网有较为详细的文档说明,现就其中一些比较绕的步骤进行总结,有问题随时交流哈. 首先微信其实已经自带分享到朋友圈,朋友,qq空间等功能,对于开发微信专门提供了一个接口,可以根据需要 ...

  7. JAVA 实现朋友圈_Java实现微信公众平台朋友圈分享功能详细代码

    其实分享的方法在微信官网有较为详细的文档说明,现就其中一些比较绕的步骤进行总结,有问题随时交流哈. 首先微信其实已经自带分享到朋友圈,朋友,qq空间等功能,对于开发微信专门提供了一个接口,可以根据需要 ...

  8. 微信公众平台开发之商品比价功能

    微信公众平台开发之商品比价功能是会员日常生活中最贴心的实用查询工具.商品比价给会员的生活带来极大的方便,也使会员对我们官方微信的依赖度提升一个层面.比价功能让我们官方微信的服务更加周到,信息更加全面, ...

  9. 微信商户平台,开通企业付款到用户零钱功能

    一.登录微信支付商户平台https://pay.weixin.qq.com 二.如果没有"企业付款到用户"产品,进入产品大全页面,将网址原网址.com后方更改为/index.php ...

最新文章

  1. Java 数值大小比较
  2. 富文本编辑器 java_Java开发之富文本编辑器TinyMCE
  3. 窗口缩小 怎么让定位的盒子不动_盒子模型
  4. 反射与二次加工标准类型
  5. 【程序设计】哨兵控制器
  6. AFNetworking网络请求的get和post步骤
  7. java 7 collection 详解(一)
  8. Linux 相关基础笔记
  9. axis调用webservice服务
  10. Linux系统入门学习
  11. 树莓派51/100 - Pico下用MicroPython在ssd1306上显示汉字
  12. 思科2960交换机配置命令
  13. 数据防泄密工作企业该如何开展
  14. HTML 文件里开头 Doctype 的作用是什么?
  15. 有n个结构体变量,内含学生学号、姓名、3门课程的成绩,要求输出平均成绩最高的学生信息
  16. 高效能人士执行4原则,让你从日常琐事中抽身
  17. Linux篇19多线程第三部分
  18. HTML一键打包APK工具(安卓应用APP)
  19. 老杨说运维 | 智能化告警在全面可观测性中的重要性
  20. 用计算机写作信息技术集体备课,信息技术集体备课总结

热门文章

  1. Wall的LocationCurve获得的墙基线位置 是否与墙的定位线有关?
  2. 机器人毕业设计题目推荐/康复机器人、(三、四、五、六度机器人)、焊接机器人、履带式搜救机器人、管道机器人、关节机器人、码垛机器人、焊接机器人、爬壁机器人、扫地机器人、喷涂机器人、搬运机器人……
  3. 压测工具:redis-benchmark与memtier_benchmark
  4. CAD和AD之间究竟有啥关系?
  5. java收到邮件后短信提醒_java邮件发送和短信发送(一)
  6. 基于51的微风扇控制器设计
  7. 初期草根站长适合做什么样的网站好
  8. 已知两点坐标,求直线方程、距离其中一点距离为L的某点
  9. 鼠标总是连击 一口君手把手教你如何解决这个问题
  10. 动力节点Redis学习笔记