Andorid微信刷脸支付使用过程解析
微信刷脸支付全部流程(普通商户号)
- 1.创建移动应用
- 2.申请商户号, 开通APP支付和刷脸支付,关联APPID
- 3.开发指引 | 微信刷脸支付
- 4.刷脸支付流程
- 名词解释
- 时序图
- 5.接口调用踩坑
- (1)初始化(initWxpayface)
- (2)获取数据 (getWxpayfaceRawdata)
- (3)获取调用凭证(get_wxpayface_authinfo)
- Sign参数获取
- (4)获取人脸支付凭证(getWxpayfaceCode)
- (5)支付 (pay),并更新支付结果(updateWxpayfacePayResult)
- 1. pay
- 2. updateWxpayfacePayResult(final Map info, final IWxPayfaceCallback wxpayfaceCallBack)
- 接口参数
- 接口返回
- 实践指引
本文着重是 开发前的准备工作和开发过程中遇到的一些坑, 不涉及 优化 ,订单查询 ,退款和 具体商户后台server的开发。
开发环境: rk开发板 +华捷艾米A200 camera
最终实现 用自己的应用和商户信息成功进行了一笔刷脸支付过程的demo 并且 不需要搭建自己的商户后台server。
1.创建移动应用
微信开放平台
在微信开放平台中创建 移动应用,填写 包名 和 签名信息 等。创建需要等审核完成,一般审核过程很快。
然后开通微信支付,未认证用户需要进行认证。认证过程也需要审核,这个比创建应用的时候要慢。
认证过程需要填写一些企业资料 和收取一定费用 ,好像是 300/年 。
2.申请商户号, 开通APP支付和刷脸支付,关联APPID
微信商户号申请
点击APP支付 申请开通
开通后 在APPID授权管理 标签页中 关联 步骤1 中所申请的 APPID (必须已经完成认证并且开通APP支付权限)。
如果APPID未认证 会提示
如果未开通APP支付权限
所以必须先要认证并且开通支付权限。
正常情况:
然后去微信开放平台 对应的APP设置中确认 关联。
至此绑定完成
3.开发指引 | 微信刷脸支付
微信刷脸支付 开发指引
微信刷脸支付SDK 目前应该也在快速迭代中,前几天还是1.30版本,现在就已经更新2.10版本了。
使用方式:
- 安装人脸App。WxPayFace 微信刷脸支付SDK
- 商户接入人脸SDK。项目中引入1中的aar包。商户APP demo
- 商户server .商户server demo 此server是在商户自己开发整套流程的参考demo ,如果只是跑通商户App demo 则不需要此server。
4.刷脸支付流程
名词解释
人脸授权 :通过人脸识别,返回微信用户信息(openid, face_code)。
face_code:人脸凭证。常用于人脸支付,作为订单的支付凭证。
时序图
注:
- 初始化 initWxpayface, 只需要在程序启动时调用;
- 释放资源 releaseWxpayface,只需要在程序退出时调用;
每个方法的具体参数可在文档内查看。接口文档
5.接口调用踩坑
(1)初始化(initWxpayface)
这个一般放在自己定义的Application#onCreate()中调用就可以了。官方示例copy即可
//对人脸SDK进行初始化
WxPayFace.getInstance().initWxpayface(this, new IWxPayfaceCallback() {@Overridepublic void response(Map info) throws RemoteException {if (info == null) {new RuntimeException("调用返回为空").printStackTrace();return ;}String code = (String) info.get("return_code");String msg = (String) info.get("return_msg");Log.d(TAG, "response info :: " + code + " | " + msg);if (code == null || !code.equals("SUCCESS")) {new RuntimeException("调用返回非成功信息: " + msg).printStackTrace();return ;}Log.d(TAG, "调用返回成功");}});
(2)获取数据 (getWxpayfaceRawdata)
此过程 一定要保证 两点:
1.设备能联网,应用要添加<uses-permission android:name="android.permission.INTERNET"/>
权限,
官方demo中还添加以下权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
2.设备有SN号 。在android设备上,开机后进入setting->about devices->status->Serial number查看
当时使用的是 rk开发板,IMG没有写入SN号。当时在论坛上找的写入SN号工具只能写入 "ro.boot.serialno"的值,"ro.serialno"还是空的,所以最后只能修改源代码,重新编译烧录版本。
/** 2. 人脸识别第二步 获取raw data*/private void getWxpayfaceRawdata() {WxPayFace.getInstance().getWxpayfaceRawdata(new IWxPayfaceCallback() {@Overridepublic void response(Map info) throws RemoteException {if (info == null) {new RuntimeException("调用返回为空").printStackTrace();return;}String code = (String) info.get("return_code");String msg = (String) info.get("return_msg");rawdata = info.get("rawdata").toString();Log.d(TAG, "rawdata ==" + rawdata);if (code == null || rawdata == null || !code.equals("SUCCESS")) {new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();return ;}/**在这里处理您自己的业务逻辑可以紧接着执行第三步 获取调用凭证getAuthInfo,这应该是向 商户server 发起请求。*/getAuthInfo(rawdata);}});}
(3)获取调用凭证(get_wxpayface_authinfo)
这是一个后端调用接口 采用xml格式
因为demo为了省事,省去商户后台server的开发,所以这一步也是在Android端直接调用。
获取凭证需要很多的 参数
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
store_id | 是 | string(32) | 门店编号, 由商户定义, 各门店唯一。 |
store_name | 是 | string(128) | 门店名称,由商户定义。(可用于展示) |
device_id | 是 | string(32) | 终端设备编号,由商户定义。 |
attach | 否 | string | 附加字段。字段格式使用Json |
rawdata | 是 | string(2048) |
初始化数据。由微信人脸SDK的接口返回。 获取方式参见: [获取数据 getWxpayfaceRawdata](#获取数据 getWxpayfaceRawdata) [获取数据 getWxpayfaceRawdata](#获取数据 getWxpayfaceRawdata) |
appid | 是 | string(32) | 商户号绑定的公众号/小程序 appid |
mch_id | 是 | string(32) | 商户号 |
sub_appid | 否 | string(32) | 子商户绑定的公众号/小程序 appid(服务商模式) |
sub_mch_id | 否 | string(32) | 子商户号(服务商模式) |
now | 是 | int | 取当前时间,10位unix时间戳。 例如:1239878956 |
version | 是 | string | 版本号。固定为1 |
sign_type | 是 | string | 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5 |
nonce_str | 是 | string(32) | 随机字符串,不长于32位 |
sign | 是 | string | 参数签名。详见微信支付签名算法 |
Sign参数获取
签名算法
签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
◆ key设置路径:微信商户平台(pay.weixin.qq.com)–>账户设置–>API安全–>密钥设置
,获取方法:
安装插件 ,浏览器最好别用QQ浏览器。
自家的插件不知道为什么唤不起来。重启N遍无用,推荐Chrome.
密钥是32位字符串 。
在上面第二步代码回调成功后紧接着 可以调用第三步。
private void getAuthInfo(String rawdata){//now 参数 是unix 10位时间戳long time = System.currentTimeMillis()/1000L;//为了对比起来方便 下面所有请求 都是用 字符串拼接的方式。//注意参数顺序 参数名ASCII码从小到大排序(字典序).String a ="appid=appid应用ID&device_id=DEV001&mch_id=mch_id商户号&nonce_str=V37ZHZVf2OrwsUV7kXTjTguP74c0byvE&now="+time+"&rawdata="+rawdata+"&sign_type=MD5&store_id=IMG001&store_name=门店名称&version=1";String stringSignTemp=a+"&key=32位的字符串";//注:key为商户平台设置的密钥keyString sign= md5(stringSignTemp).toUpperCase(); //注:MD5签名方式Log.d(TAG, "sign : " +sign);String finalStr = "<xml>\n" +" <appid>appid应用ID</appid>\n" +" <device_id>DEV001</device_id>\n" +" <nonce_str>V37ZHZVf2OrwsUV7kXTjTguP74c0byvE</nonce_str>\n" +" <now>"+time+"</now>\n" +" <mch_id>mch_id商户号</mch_id>\n" +" <rawdata>"+rawdata+"</rawdata>\n" +" <store_id>IMG001</store_id>\n" +" <store_name>门店名称</store_name>\n" +" <sign_type>MD5</sign_type>\n" +" <version>1</version>\n" +" <sign>"+sign+"</sign>\n" +"</xml>";//SSL可以不用管try {// Create a trust manager that does not validate certificate chainsfinal TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {@Overridepublic void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic java.security.cert.X509Certificate[] getAcceptedIssuers() {return new java.security.cert.X509Certificate[]{};}}};// Install the all-trusting trust managerfinal SSLContext sslContext = SSLContext.getInstance("SSL");sslContext.init(null, trustAllCerts, new java.security.SecureRandom());// Create an ssl socket factory with our all-trusting managerfinal SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();OkHttpClient client = new OkHttpClient.Builder().sslSocketFactory(sslSocketFactory).hostnameVerifier(new HostnameVerifier() {@Overridepublic boolean verify(String hostname, SSLSession session) {return true;}}).build();//请求格式xml ,请求方式postRequestBody body=RequestBody.create(MediaType.parse("application/xml"),finalStr);Request request = new Request.Builder().url("https://payapp.weixin.qq.com/face/get_wxpayface_authinfo")//后台接口地址,具体见后台开发文档.post(body).build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.d(TAG, "onFailure | getAuthInfo " + e.toString());}@Overridepublic void onResponse(Call call, Response response) throws IOException {try {String bodyStr = response.body().string();Log.d(TAG, "onResponse | getAuthInfo " + bodyStr);//这里返回的不是标准的xml格式,缺少 开始标签 ,拼接后用XmlPullParser解析String xmlStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"+bodyStr;//ReturnXMLParser 类在官方的demo中//最终获取到 AuthInfo信息。mAuthInfo = ReturnXMLParser.parseGetAuthInfoXML( new ByteArrayInputStream(xmlStr.getBytes()));} catch (Exception e) {e.printStackTrace();}}});} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}
这里需要注意的很多 :
- now 参数 注意是 10位的 时间戳 。并且拼接字符串a 时用的now 和 最后请求Body中xml内容中的Now的值一定要相同,两个地方切勿直接用 System.currentTimeMillis()/1000L
- 获取sign值 拼接的字符串a 一定要按照参数名ASCII码从小到大排序。sign值可以用签名校验工具验证
- 请求接口 https://payapp.weixin.qq.com/face/get_wxpayface_authinfo
- 返回值不是标准的xml格式,不包括
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
部分,所以可以先拼接在解析。
就这样最终拿到了AuthInfo字符串 。
(4)获取人脸支付凭证(getWxpayfaceCode)
启动人脸APP主界面入口,开启人脸识别,获取用户信息(openid)和支付凭证()。
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
appid | 是 | string | 商户号绑定的公众号/小程序 appid |
mch_id | 是 | string | 商户号 |
sub_appid | 否 | string(32) | 子商户绑定的公众号/小程序 appid(可不填) |
sub_mch_id | 否 | string(32) | 子商户号(非服务商模式不填) |
store_id | 是 | string | 门店编号 |
telephone | 否 | string | 用户手机号。用于传递会员手机,此手机将作为默认值, 填写到手机输入栏。 |
out_trade_no | 是 | string |
商户订单号,须与调用支付接口时字段一致,该字段在在face_code_type 为"1"时可不填,为"0"时必填
|
total_fee | 是 | string |
订单金额(数字), 单位分. 该字段在在face_code_type 为"1"时可不填,为"0"时必填
|
face_authtype | 是 | string |
可选值:FACEPAY : 人脸凭证,常用于人脸支付FACEPAY_DELAY : 延迟支付(提供商户号信息联系微信支付开通权限)
|
authinfo | 是 | string | 调用凭证。获取方式参见: get_wxpayface_authinfo |
ask_face_permit | 是 | string |
支付成功页是否需要展示人脸识别授权项。 展示:1 不展示:0 人脸识别授权项: 用户授权后用于1:N识别,可返回用户信息openid,建议商户有自己会员系统时,填1。 |
ask_ret_page | 否 | string | 是否展示微信支付成功页,可选值:“0”,不展示;“1”,展示 |
face_code_type | 否 | string | 目标face_code类型,可选值:“0”,人脸付款码:数字字母混合,通过「刷脸支付」接口完成支付;“1”,刷卡付款码:18位数字,通过「付款码支付/被扫支付」接口完成支付。如果不填写则默认为"0" |
ignore_update_pay_result | 否 | string | 商户端是否对SDK返回支付结果,可选值:“0”,返回支付结果,商户需在确认⽀付结果后调⽤[updateWxpayfacePayResult]通知SDK;“1”,不返回支付结果。如果不填写则默认为"0"。 |
private void getWXPayFaceCode(String mAuthInfo){if (mAuthInfo== null){Log.d(TAG, "mAuthInfo 为 null");return;}HashMap params = new HashMap();params.put(BaseUtils.FACE_AUTHTYPE, "FACEPAY");params.put(BaseUtils.APPID, "wxefawffetat56");params.put(BaseUtils.MCH_ID, "11534ef6121");params.put(BaseUtils.STORE_ID, "IMG001");//订单号 ,注意后后面支付pay中的订单号要一致out_trade_no = "" +(System.currentTimeMillis() / 100000); params.put(BaseUtils.OUT_TRADE_NO, out_trade_no);//订单金额params.put(BaseUtils.TOTAL_FEE, "1");//第三步中获取的AuthInfoparams.put(BaseUtils.AUTHINFO, mAuthInfo);WxPayFace.getInstance().getWxpayfaceCode(params, new IWxPayfaceCallback() {@Overridepublic void response(final Map info) throws RemoteException {// if (!isSuccessInfo(info)) {// return;
// }Log.d(TAG, "response | getWxpayfaceCode" );final String code = (String)info.get(BaseUtils.RETURN_CODE);// open id , face coderunOnUiThread(new Runnable() {@Overridepublic void run() {//请求成功if (TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_SUCCESS)) {//获取openid 和 face_code face_code = (String)info.get("face_code");openID = (String)info.get("openid");ip = "174.207.250.66";try {Thread.sleep(2000);//第5步 支付pay(openID,face_code,ip);} catch (Exception e) {}} else if (TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_USER_CANCEL)) {Log.d(TAG, "run: 用户取消");} else if (TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_SCAN_PAYMENT)) {Log.d(TAG, "run: 扫码支付");} else if (TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_ERROR)) {Log.d(TAG, "run: 发生错误");}}});}});}
这个过程没什么说的,就是用第三步的AuthInfo ,还有就是订单号 要和后面第五步支付过程的订单号要保持一致。
(5)支付 (pay),并更新支付结果(updateWxpayfacePayResult)
1. pay
支付 同样是一个后端server接口 后端server接口
接口地址 :https://api.mch.weixin.qq.com/pay/facepay
请求方式 POST、XML
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
appid | 是 | string | 商户号绑定的公众号/小程序 appid |
mch_id | 是 | string | 商户号 |
sub_appid | 否 | string(32) | 子商户绑定的公众号/小程序 appid(可不填) |
sub_mch_id | 否 | string(32) | 子商户号(非服务商模式不填) |
device_info | 否 | string(32) | 终端设备号(商户自定义,如门店编号)。 |
out_trade_no | 是 | string(32) | 商户系统内部的订单号,32个字符内、可包含字母;更换授权码必须要换新的商户订单号 其他说明见商户订单号 |
total_fee | 是 | string |
订单金额(数字), 单位分. 该字段在在face_code_type 为"1"时可不填,为"0"时必填
|
nonce_str | 是 | string(32) | 随机字符串,不长于32位。推荐随机数生成算法 |
sign | 是 | string(32) | 参数签名。详见微信支付签名算法 |
body | 是 | String(128) | 商品或支付单简要描述,格式要求:门店品牌名-城市分店名-实际商品名称 |
total_fee | 是 | Int | 订单总金额,单位为分,只能为整数,详见支付金额 |
spbill_create_ip | 是 | String(16) | 调用微信支付API的机器IP |
openid | 是 | String(128) | 用户在商户appid 下的唯一标识 |
face_code | 是 | String(128) | 人脸凭证,用于刷脸支付 |
更多不必要参数可查看文档。
举例如下:
<xml><appid>wx2421b1c4370ec43b</appid><attach>订单额外描述</attach><body>刷卡支付测试</body><device_info>1000</device_info><goods_tag></goods_tag><mch_id>10000100</mch_id><nonce_str>8aaee146b1dee7cec9100add9b96cbe2</nonce_str><out_trade_no>1415757673</out_trade_no><spbill_create_ip>14.17.22.52</spbill_create_ip><time_expire></time_expire><total_fee>1</total_fee><openid><![CDATA[oUpF8uN95-Ptaags6E_roPHg7AG0]]></openid><face_code>Qpoqwhsdjhfausrhqieofnq90w=w8233wdwjdjiwq</face_code><sign>C29DB7DB1FD4136B84AE35604756362C</sign>
</xml>
pay方法中Http请求 返回结果请查看文档
2. updateWxpayfacePayResult(final Map info, final IWxPayfaceCallback wxpayfaceCallBack)
接口参数
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
appid | 是 | string | 商户绑定的公众号/小程序 appid |
mch_id | 是 | string | 商户号 |
store_id | 是 | string | 门店编号 |
authinfo | 是 | string | 调用凭证。获取方式参见: get_wxpayface_authinfo |
payresult | 是 | string |
支付结果。可取值:SUCCESS : 支付成功ERROR : 支付失败
|
接口返回
参数 | 必填 | 类型 | 说明 |
---|---|---|---|
return_code | 是 | string | 错误码。公共定义见 公共错误码 |
return_msg | 是 | string(128) | 对错误码的描述 |
实践指引
private void updateWxpayfacePayResult() {HashMap<String, String> map = new HashMap<String, String>();map.put("appid", "填您的公众号"); // 公众号,必填map.put("mch_id", "填您的商户号"); // 商户号,必填map.put("store_id", "填您的门店编号"); // 门店编号,必填map.put("authinfo", "填您的调用凭证"); // 调用凭证,必填map.put("payresult", "SUCCESS"); // 支付结果,SUCCESS:支付成功 ERROR:支付失败 必填WxPayFace.getInstance().updateWxpayfacePayResult(map, new IWxPayfaceCallback() {@Overridepublic void response(Map info) throws RemoteException {if (info == null) {new RuntimeException("调用返回为空").printStackTrace();return;}String code = (String) info.get("return_code"); // 错误码String msg = (String) info.get("return_msg"); // 错误码描述if (code == null || !code.equals("SUCCESS")) {new RuntimeException("调用返回非成功信息,return_msg:" + msg + " ").printStackTrace();return ;}/*在这里处理您自己的业务逻辑:执行到这里说明用户已经确认支付结果且成功了,此时刷脸支付界面关闭,您可以在这里选择跳转到其它界面*/}});}
最后第五步整体过程代码:
private void pay(String openID,String faceCode,String ipAddress){Log.d(TAG, "-------------start pay-----------");String a ="appid=APPID&body=刷脸支付测试&device_info=DEV001&face_code="+faceCode+"&mch_id=MCH_ID&nonce_str=V37ZHZVf2OrwsUV7kXTjTguP74c0byvE&openid="+openID+"&out_trade_no="+out_trade_no+"&spbill_create_ip="+ipAddress+"&total_fee=1";String stringSignTemp=a+"&key=32KEY";//注:key为商户平台设置的密钥keyString sign= md5(stringSignTemp).toUpperCase();String finalStr = "<xml>\n" +" <appid>APPID</appid>\n" +" <body>刷脸支付测试</body>\n" +" <device_info>DEV001</device_info>\n"+" <face_code>"+faceCode+"</face_code>\n"+" <mch_id>MCHID</mch_id>\n" +" <nonce_str>V37ZHZVf2OrwsUV7kXTjTguP74c0byvE</nonce_str>\n" +" <openid>"+openID+"</openid>\n"+" <out_trade_no>"+out_trade_no+"</out_trade_no>\n"+" <spbill_create_ip>"+ipAddress+"</spbill_create_ip>\n" +" <total_fee>1</total_fee>\n"+" <sign>"+sign+"</sign>\n" +"</xml>";OkHttpClient client = new OkHttpClient.Builder().hostnameVerifier(new HostnameVerifier() {@Overridepublic boolean verify(String hostname, SSLSession session) {return true;}}).build();RequestBody body=RequestBody.create(MediaType.parse("application/xml"),finalStr);Request request = new Request.Builder().url("https://api.mch.weixin.qq.com/pay/facepay").post(body).build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.d(TAG, "onFailure | getAuthInfo " + e.toString());}@Overridepublic void onResponse(Call call, Response response) throws IOException {try {String bodyStr = response.body().string();Log.d(TAG, "支付结果 ====\n" + bodyStr);String xmlStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"+bodyStr;
// String retrunCode = ReturnXMLParser.parseCodeXML( new ByteArrayInputStream(xmlStr.getBytes()),"return_code");String result_code = ReturnXMLParser.parseCodeXML( new ByteArrayInputStream(xmlStr.getBytes()),"result_code");Map map =new HashMap();map.put("appid","APPID应用ID");map.put("mch_id",商户号);map.put("store_id","IMG001");map.put("authinfo",mAuthInfo);boolean resultStatus = TextUtils.equals(result_code, WxfacePayCommonCode.VAL_RSP_PARAMS_SUCCESS);if (result_code!=null && resultStatus ){map.put("payresult","SUCCESS");}else {map.put("payresult","ERROR");}//更新支付状态 WxPayFace.getInstance().updateWxpayfacePayResult(map, new IWxPayfaceCallback() {@Overridepublic void response(Map info) throws RemoteException {Log.d(TAG, "-------------更新支付状态 -----------"+info.get("return_code"));}});} catch (Exception e) {e.printStackTrace();}}});}
请求成功后一定要 调用更新支付结果的方法(不然一直卡在 支付等待界面),调用后会根据结果提示支付成功或者失败。 至此整个支付流程就完事了。
最后可以去商户平台 查看订单信息:
Andorid微信刷脸支付使用过程解析相关推荐
- python读取excel单元格填充色rgb_Python openpyxl读取单元格字体颜色过程解析
Python openpyxl读取单元格字体颜色过程解析 问题 我试图打印some_cell.font.color.rgb并得到各种结果. 对于一些人,我得到了我想要的东西(比如" FF00 ...
- JAVA接入微信刷脸支付分支付【V2、V3两种接入都有提供】
支付宝支付 开发前准备 文档 开发准备 maven 微信配置类 微信V2-SDK 微信V3工具 开发调用 V2刷脸授权接口[get_wxpayface_authinfo] V3支付相关接口[接口太多部 ...
- 微信刷脸支付开放政策启动,亿万级市场待你加入!
当大家认为扫码支付已是未来的支付方式时,支付宝与微信两大行业巨头,却用实际行动告诉我们,未来移动支付是不需要手机的,靠脸就能走天下,刷脸支付正在革新扫码支付,成为2019年支付生态的重头戏. 5月22 ...
- android微信刷脸支付宝,录指纹、敲密码太麻烦,OPPO Find X完成安卓首个微信刷脸支付...
原标题:录指纹.敲密码太麻烦,OPPO Find X完成安卓首个微信刷脸支付 科技改变生活,最直观的体现就是能够将过去的一些方式摒弃掉,用新科技来替代,最好的代表就是现如今越来越多的人只带一部手机就出 ...
- 客快物流大数据项目(十四):DockerFile介绍与构建过程解析
目录 DockerFile介绍与构建过程解析 一.什么是Dockerfile 1.介绍 2.Dockerfile构建步骤
- java操作es聚合操作并显示其他字段_java使用elasticsearch分组进行聚合查询过程解析...
这篇文章主要介绍了java使用elasticsearch分组进行聚合查询过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 java连接elas ...
- aop springboot 传入参数_java相关:springboot配置aop切面日志打印过程解析
java相关:springboot配置aop切面日志打印过程解析 发布于 2020-3-31| 复制链接 摘记: 这篇文章主要介绍了springboot配置aop切面日志打印过程解析,文中通过示例代码 ...
- python画散点图程序-Python散点图与折线图绘制过程解析
这篇文章主要介绍了Python散点图与折线图绘制过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在数据分析的过程中,经常需要将数据可视化,目 ...
- Apache ZooKeeper -从初始化到对外提供服务的过程解析( 集群模式 )
文章目录 流程图 Pre 什么是集群模式? ZooKeeper 集群模式的特点 底层实现原理 程序启动 QuorumPeer 类 Leader 服务器启动过程 Follow 服务器启动过程 小结 流程 ...
最新文章
- 1.8 finally和return的执行顺序
- linux下批量修改文件名的方法
- Python基础day05 作业解析【10道 函数作业题】
- [Project Euler] 来做欧拉项目练习题吧: 题目004
- 第十七章 特殊类成员
- 风客科技网管培训资料
- android 按钮点击返回顶部,微信浏览器点击系统返回,安卓返回会重载页面回到页面顶部,iOS则返回则会保留之前浏览位置的解决方法...
- React Native RSA加密
- thinkphp5 图片压缩旋转_有非常多的图片,该怎么制作PPT?
- Kafka高可用机制入门
- BZOJ 2756: [SCOI2012]奇怪的游戏
- IOS第11天(4:UIDatePicker时间选择,和键盘处理,加载xib文件,代理模式)
- 10个线程同时执行i++操作1000次,如何保证结果是1w
- SocksCap64全局代理设置教程
- void value not ignored as it ought to be
- Qt 信号与槽机制及实战案例
- XP需要计算机管理权限,xp无法无法使用管理员权限运行软件的解决步骤
- 信息系统项目管理9大知识领域及其概要说明
- chrome控制台设置网页自动刷新
- 以分割栅格为例实现FME模板的方案优化
热门文章
- fedora13中安装五笔
- html 语言怎么弄英语,HTML语言,HTML language,音标,读音,翻译,英文例句,英语词典
- win10禁用全角,教你恢复win10系统屏蔽全角/半角快捷键的办法
- 基带、射频,到底是什么?
- 小数输出最简分数c语言,小数化成最简式分数
- 如何从零基础入门并精通PS?PS如何快速入门?
- Android Launcher启动流程
- 论文经验 - 计算机视觉(CV)方向
- ssm+bootsrap人力资源考勤系统-JAVA【数据库设计、源码、开题报告】
- html5 mp3播放器源码,HTML5自定义mp3播放器源码