支付宝刷脸模块

This commit is contained in:
张雪 2025-05-07 10:06:16 +08:00
parent d46490fc6b
commit 237cf8dbe3
8 changed files with 204 additions and 45 deletions

View File

@ -1,16 +1,22 @@
package com.dpkj.modules.scanface.ali.controller;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.dpkj.common.vo.Result;
import com.dpkj.modules.scanface.ali.config.AliFaceConfig;
import com.dpkj.modules.scanface.ali.constants.AliFaceConstants;
import com.dpkj.modules.scanface.ali.dll.AbcpInvoke;
import com.dpkj.modules.scanface.ali.service.IAliScanFaceService;
import com.dpkj.modules.scanface.ali.vo.MyCallbackRsp;
import com.dpkj.modules.scanface.ali.vo.AliOrderVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@ -35,6 +41,21 @@ public class AliScanFaceController {
@Resource
private AliFaceConfig aliFaceConfig;
/**
* 完整的统一的支付宝刷脸支付
* 1调用硬件刷脸获取到ftoken
* 2调用后端的支付宝支付存入hispay
* @param aliOrderVo
* @return
* @throws Exception
*/
@PostMapping("/aliFacePay")
public Result<JSONObject> aliFacePay(@RequestBody AliOrderVo aliOrderVo) throws Exception {
return aliScanFaceService.aliFacePay(aliOrderVo);
}
/**
* ABCP初始化
* 文档地址https://opendocs.alipay.com/iot/05e9ye
@ -73,6 +94,8 @@ public class AliScanFaceController {
/**
* ABCP服务停用
* 终止正在进行中的某次service_code + traceId或某类service_code服务调用
* 如处于支付环节此次服务调用将不接受停止
* @param traceId
* @return
*/

View File

@ -1,13 +1,20 @@
package com.dpkj.modules.scanface.ali.service;
import com.alibaba.fastjson.JSONObject;
import com.dpkj.common.vo.Result;
import com.dpkj.modules.scanface.ali.vo.AliOrderVo;
public interface IAliScanFaceService {
/**
* 初始化
Result<Object> iniAbcp() ;
* 完整的统一的支付宝刷脸支付
* 1调用硬件刷脸获取到ftoken
* 2调用后端的支付宝支付存入hispay记录
* @param aliOrderVo
* @return
* @throws Exception
*/
Result<JSONObject> aliFacePay(AliOrderVo aliOrderVo);
/**
* 初始化调用阿里的ABCP_SDK部署出来的代码中的API文件
@ -31,6 +38,7 @@ public interface IAliScanFaceService {
/**
* ABCP服务停用
* 终止正在进行中的某次service_code + traceId或某类service_code服务调用然后通过回调返回服务终止结果
* 如处于支付环节此次服务调用将不接受停止
* @param json 组装参数
* @param service_code 组件编码
* @return

View File

@ -1,14 +1,21 @@
package com.dpkj.modules.scanface.ali.service.impl;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSON;
import com.dpkj.common.vo.Result;
import com.dpkj.modules.scanface.ali.config.AliFaceConfig;
import com.dpkj.modules.scanface.ali.constants.AliFaceConstants;
import com.dpkj.modules.scanface.ali.dll.AbcpInvoke;
import com.dpkj.modules.scanface.ali.service.IAliScanFaceService;
import com.dpkj.modules.scanface.ali.vo.MyCallbackRsp;
import com.dpkj.modules.scanface.ali.vo.AliOrderVo;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.StringUtils;
@ -20,6 +27,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* @Auther: 萧道子
* @Date: 2025/4/16 16:47
@ -27,16 +35,78 @@ import java.util.concurrent.atomic.AtomicReference;
*/
@Slf4j
@Service
@Component
public class AliScanFaceServiceImpl implements IAliScanFaceService {
@Value("${dpkj.serverurl}")
private String serverUrl;
@Resource
private AliFaceConfig aliFaceConfig;
/**
* 使用绝对路径调用ABCP_SDK部署出来的AbcpInvoke类
*
* @return
* @description: * 完整的统一的支付宝刷脸支付
* 1调用硬件刷脸获取到ftoken
* 2调用后端的支付宝支付存入hispay
* @author: zhangxue
* @date: 2025/5/7 9:45
* @Param [aliOrderVo]
* @return: com.dpkj.common.vo.Result<com.alibaba.fastjson.JSONObject>
*/
@Override
public Result<JSONObject> aliFacePay(AliOrderVo aliOrderVo) {
try {
/**
* 1获取刷脸"刷脸去初始化服务"的ftoken返回值
*/
this.iniAbcpAbsolute();
//参数
JSONObject zolozConfig = new JSONObject().fluentPut("installAngle", 90);
JSONObject params = new JSONObject()
.fluentPut("serviceId", aliFaceConfig.getServiceId())
.fluentPut("zolozConfig", zolozConfig);
String json = params.toJSONString();
String service_code = AliFaceConstants.SMILEVERIFYNIN_V1; //调用的组件编码:初始化
Result<Object> startServiceIniResult = this.startServiceIni(json, service_code);
if (startServiceIniResult.isSuccess()) {
Map<String, String> res = (Map<String, String>) startServiceIniResult.getResult();
String ftoken = res.get("ftoken");
/**
* 2调用后端的支付宝统一收单交易支付接口存入hisPay
*/
aliOrderVo.setAuthCode(ftoken);//Demo值"fp128d26333fa66e66e7f34c493d30cdh76"
JSONObject serverParams = (JSONObject) JSON.toJSON(aliOrderVo);
String url = serverUrl + "openapi/aliPayOrderApi/createOrder";
String req = HttpRequest.post(url)
.header(Header.CONTENT_TYPE, ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8))
.body(serverParams.toJSONString())
.execute()
.body();
JSONObject serverResult = JSONObject.parseObject(req);
return Result.ok(serverResult);
} else {
//调用ABCP 刷脸初始化服务失败
log.error("[AliScanFaceServiceImpl][aliFacePay][299]调用ABCP 刷脸初始化服务失败 {}", startServiceIniResult.getMessage());
return Result.error(startServiceIniResult.getMessage());
}
} catch (Exception e) {
log.error("[AliScanFaceServiceImpl][aliFacePay][302][整个支付宝刷脸模块出现失败:] {}", e.getMessage());
return Result.error("支付宝刷脸失败:" + e.getMessage());
}
}
/**
* @description: 使用绝对路径调用ABCP_SDK部署出来的AbcpInvoke类
* @author: zhangxue
* @date: 2025/5/7 9:45
* @Param []
* @return: com.dpkj.common.vo.Result<java.lang.Object>
*/
@Override
public Result<Object> iniAbcpAbsolute() {
@ -87,6 +157,7 @@ public class AliScanFaceServiceImpl implements IAliScanFaceService {
* ABCP服务调用 刷脸初始化服务,获取ftoken
* 接受调用者传入的参数信息执行指定服务service_code然后通过回调返回服务结果
* https://opendocs.alipay.com/iot/05e9ye#ABCP%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8
*
* @param json 组装参数
* @param service_code 所要调用的组件编码
* @return
@ -114,7 +185,7 @@ public class AliScanFaceServiceImpl implements IAliScanFaceService {
AbcpInvoke.CallbackRsp callbackRsp = new AbcpInvoke.CallbackRsp() {
@Override
public void OnProcess(int code, String subCode, String subMsg, String result) {
log.info("[AliScanFaceServiceImpl][OnProcess][123][service_code:{}][code:{}][subCode:{}][subMsg:{}][result:{}]",service_code, code, subCode, subMsg, result);
log.info("[AliScanFaceServiceImpl][OnProcess][123][service_code:{}][code:{}][subCode:{}][subMsg:{}][result:{}]", service_code, code, subCode, subMsg, result);
try {
processCode.set(code);
processResult.set(result);
@ -125,7 +196,7 @@ public class AliScanFaceServiceImpl implements IAliScanFaceService {
@Override
public void OnFinish(int code, String subCode, String subMsg, String result) {
log.info("[AliScanFaceServiceImpl][OnFinish][128][service_code:{}][code:{}][subCode:{}][subMsg:{}][result:{}]",service_code, code, subCode, subMsg, result);
log.info("[AliScanFaceServiceImpl][OnFinish][128][service_code:{}][code:{}][subCode:{}][subMsg:{}][result:{}]", service_code, code, subCode, subMsg, result);
/**Demo示例记录
* [service_code:BPaaSSmileVerifyNonInitV1][code:1000][subCode:E00000][subMsg:SUCCESS][result:{"code":1000,"subCode":"OK_SUCCESS","subMessage":"SUCCESS","barCode":"281215320962898068","ftoken":"fp1efd3d4c0230a28f5261efe7c5050eh28","alipayUid":"2088812449506047","accountList":"[\"104***@qq.com\"]","authToken":"44686f7195c77ee2e09c09bcdc657dd5h28i","result":{"accountList":["104***@qq.com"],"alipayUid":"2088812449506047","allowRetry":false,"authToken":"44686f7195c77ee2e09c09bcdc657dd5h28i","barCode":"281215320962898068","certName":"您好,*雪","ftoken":"fp1efd3d4c0230a28f5261efe7c5050eh28","type":"selectUid"},"easterEgg":false,"zolozConfig":{"installAngle":90},"serviceId":"pay","traceId":"2444-44-1745802328","callStartTimeMs":1745802328114,"localTime":"2025-04-28-09-05-41-791"}]
@ -168,7 +239,7 @@ public class AliScanFaceServiceImpl implements IAliScanFaceService {
if (finishCode.get() == 1000) {
JSONObject jsonObject = JSONObject.parseObject(finishResult.get());
if (jsonObject.containsKey("ftoken")) {
res.put("ftoken", jsonObject.getString("ftoken"));
res.put("ftoken", jsonObject.getString("ftoken"));//ftoken参数的有效期为2分钟
res.put("barCode", jsonObject.getString("barCode"));
finishResultRef.set(Result.ok("ABCP调用刷脸初始化finish服务成功", res));
} else {
@ -188,10 +259,11 @@ public class AliScanFaceServiceImpl implements IAliScanFaceService {
}
/**
* ABCP服务停用
* 终止正在进行中的某次service_code + traceId或某类service_code服务调用然后通过回调返回服务终止结果
* 如处于支付环节此次服务调用将不接受停止
*
* @param json 组装参数
* @param service_code 组件编码
* @return
@ -209,12 +281,12 @@ public class AliScanFaceServiceImpl implements IAliScanFaceService {
AbcpInvoke.CallbackRsp callbackRsp = new AbcpInvoke.CallbackRsp() {
@Override
public void OnProcess(int code, String subCode, String subMsg, String result) {
log.info("[AliScanFaceServiceImpl][261][ABCP服务停用-OnProcess][code:{}][subCode:{}][subMsg:{}][result:{}]", code, subCode, subMsg, result);
log.info("[AliScanFaceServiceImpl][261][ABCP服务停用-OnProcess][code:{}][subCode:{}][subMsg:{}][result:{}]", code, subCode, subMsg, result);
}
@Override
public void OnFinish(int code, String subCode, String subMsg, String result) {
log.info("[AliScanFaceServiceImpl][OnFinish][266][ABCP服务停用-OnFinish] [code:{}][subCode:{}][subMsg:{}][result:{}]", code, subCode, subMsg, result);
log.info("[AliScanFaceServiceImpl][OnFinish][266][ABCP服务停用-OnFinish] [code:{}][subCode:{}][subMsg:{}][result:{}]", code, subCode, subMsg, result);
try {
returnCode.set(code);
returnResult.set(result);
@ -234,7 +306,7 @@ public class AliScanFaceServiceImpl implements IAliScanFaceService {
return Result.error("等待回调超时");
} else {
if (returnCode.get() == 0) {
System.out.println("停止结果:"+returnResult.get());
System.out.println("停止结果:" + returnResult.get());
} else {
return Result.error("ABCP停止服务失败");
}

View File

@ -0,0 +1,81 @@
package com.dpkj.modules.scanface.ali.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @description: 支付宝支付参数传入统一下单接口
* @author: Zhangxue
* @time: 2025/4/29 14:24
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class AliOrderVo implements Serializable {
/**
* 付款模块
*/
private String eventModule;
/**
* 患者Id
*/
private String patientId;
/**
* 商户机具终端编号
*/
private String terminalId;
/**
* 系统订单编号
*/
private String outTradeNo;
/**
* 用户支付金额
*/
//@ApiModelProperty(value = "用户支付金额")
private String totalAmount;
/**
* 订单标题
*/
//@ApiModelProperty(value = "订单标题")
private String subject;
/**
* 支付授权码
* 刷脸标识串fp开头的35位字符串
* 从调用"BPaaSSmileVerifyNonInitV1"服务中获取
*/
//@ApiModelProperty(value = "支付授权码")
private String authCode;
/**
* 支付场景
* bar_code当面付条码支付场景默认值
* security_code当面付刷脸支付场景对应的auth_code为fp开头的刷脸标识串
*/
//@ApiModelProperty(value = "支付授权码")
private String scene;
/**
* 产品码:商家和支付宝签约的产品码
* 当面付场景下如果签约的是当面付快捷版则传 OFFLINE_PAYMENT;
* 其它支付宝当面付产品传 FACE_TO_FACE_PAYMENT
* 不传则默认使用FACE_TO_FACE_PAYMENT
*/
//@ApiModelProperty(value = "订单标题")
private String productCode;
/**
* 卖家支付宝用户ID
*/
//@ApiModelProperty(value = "订单标题")
private String sellerId;
}

View File

@ -1,30 +0,0 @@
package com.dpkj.modules.scanface.ali.vo;
import com.dpkj.common.vo.Result;
import com.dpkj.modules.scanface.ali.dll.AbcpInvoke;
import lombok.extern.slf4j.Slf4j;
/**
* @description: 自定义回调实现类
* @author: Zhangxue
* @time: 2025/4/15 20:41
*/
@Slf4j
public class MyCallbackRsp implements AbcpInvoke.CallbackRsp {
@Override
public void OnProcess(int code, String subCode, String subMsg, String result) {
// 处理初始化过程中的中间状态如进度更新
log.info("[MyCallbackRsp][OnProcess][18][OnProcess] code=%d, subCode=%s, subMsg=%s, result=%s%n", code, subCode, subMsg, result);
}
@Override
public void OnFinish(int code, String subCode, String subMsg, String result) {
// 处理初始化完成结果
if (code == 0) {
log.info("[MyCallbackRsp][OnFinish][27][返回结果:] {}", result);
} else {
log.info("[MyCallbackRsp][OnFinish][29] :初始化失败!错误码: %s, 错误信息: %s%n", subCode, subMsg);
}
}
}

View File

@ -2,6 +2,8 @@ server:
port: 5948
dpkj:
#后端项目访问地址 #https://yinyitong.yzqingyan.cn/ http://172.16.11.13:15946/ ttps://yinyitong.yzqingyan.cn
serverurl: http://localhost:5946/api/
# 医保配置
chs:
# 医保机构编码

View File

@ -2,6 +2,9 @@ server:
port: 5946
dpkj:
#后端项目访问地址
#TODO 改为正式的地址 http://www.lczyyy.com/api
serverurl: http://127.0.0.1:15946/api
# 医保配置
chs:
# 医保机构编码

View File

@ -22,4 +22,4 @@ spring:
application:
name: ems-express-bridge
profiles:
active: pro
active: dev