微信刷脸SDK
This commit is contained in:
parent
ee0b1ac055
commit
6dac863d45
|
@ -0,0 +1,81 @@
|
|||
package com.dpkj.modules.scanface.wx.config;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/11/28 9:38
|
||||
*/
|
||||
|
||||
public class WechatUrlConfig {
|
||||
|
||||
/**
|
||||
* 获取证书
|
||||
*/
|
||||
public static final String CERTIFICATESURL = "https://api.mch.weixin.qq.com/v3/certificates";
|
||||
|
||||
|
||||
/**
|
||||
* 退款地址
|
||||
*/
|
||||
public static final String REFUNDSURL = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
|
||||
|
||||
/**
|
||||
* 创建支付分订单
|
||||
*/
|
||||
public static final String SERVICEORDER = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder";
|
||||
|
||||
|
||||
/**
|
||||
* 发起订单支付
|
||||
*/
|
||||
public static final String CREATEORDER = "https://api.mch.weixin.qq.com/pay/micropay";
|
||||
|
||||
/**
|
||||
* 查询订单状态
|
||||
*/
|
||||
public static final String ORDERQUERY = "https://api.mch.weixin.qq.com/pay/orderquery";
|
||||
|
||||
|
||||
/**
|
||||
* 撤销交易
|
||||
*/
|
||||
public static final String REVERSE = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
|
||||
|
||||
/**
|
||||
* 取消支付分订单前缀
|
||||
*/
|
||||
public static final String ORDERCANCELPREFIX = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder/";
|
||||
|
||||
/**
|
||||
* 取消支付分订单后缀
|
||||
*/
|
||||
public static final String ORDERCANCELSUFFIX = "/cancel";
|
||||
|
||||
/**
|
||||
* 完结支付分订单前缀
|
||||
*/
|
||||
public static final String SERVICEORDERCOMPLETEPREFIX = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder/";
|
||||
|
||||
|
||||
/**
|
||||
* 完结支付分订单后缀
|
||||
*/
|
||||
public static final String SERVICEORDERCOMPLETESUFFIX = "/complete";
|
||||
|
||||
/**
|
||||
* 获取调用凭证
|
||||
*/
|
||||
public static final String GET_WXPAYFACE_AUTHINFO = "https://payapp.weixin.qq.com/face/get_wxpayface_authinfo";
|
||||
|
||||
|
||||
/**
|
||||
* 查询订单
|
||||
*/
|
||||
public static final String FINDBYID = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder";
|
||||
|
||||
/**
|
||||
* 查询退款订单
|
||||
*/
|
||||
public static final String FINDREFUND = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/";
|
||||
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
package com.dpkj.modules.scanface.wx.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公众号配置
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "wx.mp")
|
||||
public class WxMpProperties {
|
||||
/**
|
||||
* 是否使用redis存储access token
|
||||
*/
|
||||
private Boolean useRedis = false;
|
||||
|
||||
/**
|
||||
* redis 配置
|
||||
*/
|
||||
private RedisConfig redisConfig;
|
||||
|
||||
@Data
|
||||
public static class RedisConfig {
|
||||
/**
|
||||
* redis服务器 主机地址
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* redis服务器 端口号
|
||||
*/
|
||||
private Integer port;
|
||||
|
||||
/**
|
||||
* redis服务器 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* redis 服务连接超时时间
|
||||
*/
|
||||
private Integer timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个公众号配置信息
|
||||
*/
|
||||
private List<MpConfig> configs;
|
||||
|
||||
@Data
|
||||
public static class MpConfig {
|
||||
/**
|
||||
* 设置微信公众号的appid
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的app secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的EncodingAESKey
|
||||
*/
|
||||
private String aesKey;
|
||||
|
||||
/**
|
||||
* 微信:调用接口所需service_id
|
||||
*/
|
||||
private String serviceId;
|
||||
|
||||
/**
|
||||
* 微信:商户号
|
||||
*/
|
||||
private String mchId;
|
||||
|
||||
/**
|
||||
* 微信支付商户密钥
|
||||
*/
|
||||
private String mchKey;
|
||||
|
||||
/**
|
||||
* 微信:报文解密V3密钥key
|
||||
*/
|
||||
private String v3Key;
|
||||
|
||||
/**
|
||||
* 微信: API密钥
|
||||
*/
|
||||
private String keyApi;
|
||||
|
||||
/**
|
||||
* 微信:密钥【apiclient_key.pem】地址
|
||||
p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath;开头)
|
||||
*/
|
||||
private String keyPath;
|
||||
|
||||
/**
|
||||
* 微信:商家api序列号
|
||||
*/
|
||||
private String mchSerialNo;
|
||||
|
||||
/**
|
||||
* #JSAPI--公众号支付 NATIVE--原生扫码支付 APP--app支付
|
||||
*/
|
||||
private String tradeType;
|
||||
|
||||
/**
|
||||
* 微信:支付回调地址
|
||||
*/
|
||||
private String payNotifyUrl;
|
||||
|
||||
/**
|
||||
* 微信:退款回调地址
|
||||
*/
|
||||
private String refundNotifyUrl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 访问地址
|
||||
*/
|
||||
private MpUrl url;
|
||||
|
||||
@Data
|
||||
public static class MpUrl {
|
||||
/**
|
||||
* H5地址
|
||||
*/
|
||||
private String h5;
|
||||
|
||||
/**
|
||||
* 接口地址
|
||||
*/
|
||||
private String server;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板消息id
|
||||
*/
|
||||
private MpTemplate template;
|
||||
|
||||
@Data
|
||||
public static class MpTemplate {
|
||||
/**
|
||||
* 缴费通知
|
||||
*/
|
||||
private String payMsg;
|
||||
|
||||
/**
|
||||
* 流程待办
|
||||
*/
|
||||
private String test;
|
||||
|
||||
/**
|
||||
* 流程待办
|
||||
*/
|
||||
private String test2;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信商户支付配置
|
||||
*/
|
||||
private MchConfig mchConfig;
|
||||
@Data
|
||||
public static class MchConfig{
|
||||
/**
|
||||
* 微信:APPID
|
||||
*/
|
||||
private String appId;
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 微信:商户号
|
||||
*/
|
||||
private String mchId;
|
||||
//微信支付商户密钥
|
||||
private String mchKey;
|
||||
|
||||
/**
|
||||
* 微信:报文解密V3密钥key
|
||||
*/
|
||||
private String v3Key;
|
||||
|
||||
/**
|
||||
* 微信: API密钥
|
||||
*/
|
||||
private String keyApi;
|
||||
|
||||
/**
|
||||
* 微信:密钥【apiclient_key.pem】地址
|
||||
p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath;开头)
|
||||
*/
|
||||
private String keyPath;
|
||||
|
||||
/**
|
||||
* 退款证书 private-key-path V3
|
||||
* apiclient_key.pem 证书文件的绝对路径或者以classpath:开头的类路径.
|
||||
*/
|
||||
private String privateKeyPath;
|
||||
|
||||
/**
|
||||
* 退款证书 private-cert-path
|
||||
* apiclient_cert.pem 证书文件的绝对路径或者以classpath:开头的类路径.
|
||||
*/
|
||||
private String privateCertPath;
|
||||
|
||||
|
||||
/**
|
||||
* 微信:商家api序列号
|
||||
*/
|
||||
private String mchSerialNo;
|
||||
|
||||
/**
|
||||
* 微信:调用接口所需service_id
|
||||
*/
|
||||
private String serviceId;
|
||||
|
||||
|
||||
/**
|
||||
* 微信:支付回调地址
|
||||
*/
|
||||
private String payNotifyUrl;
|
||||
|
||||
|
||||
/**
|
||||
* 微信:退款回调地址
|
||||
*/
|
||||
private String refundNotifyUrl;
|
||||
|
||||
/**
|
||||
* #JSAPI--公众号支付 NATIVE--原生扫码支付 APP--app支付
|
||||
*/
|
||||
private String tradeType;
|
||||
|
||||
/**
|
||||
* NATIVE--原生扫码支付
|
||||
*/
|
||||
private String tradeTypeNative;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
package com.dpkj.modules.scanface.wx.controller;
|
||||
|
||||
import com.dpkj.common.vo.Result;
|
||||
import com.dpkj.modules.scanface.wx.dll.WxpayFaceSDKDll;
|
||||
import com.dpkj.modules.scanface.wx.service.CallWxpayFaceService;
|
||||
import com.dpkj.modules.scanface.wx.service.WeChatPayFaceService;
|
||||
import com.dpkj.modules.scanface.wx.service.impl.CallWxpayFaceServiceImpl;
|
||||
import com.dpkj.modules.scanface.wx.service.impl.WeChatPayFaceServiceImpl;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayAuthinfoResp;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayReq;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayResp;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/11/28 16:43
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/wxpayFace")
|
||||
public class WxpayFaceTestController {
|
||||
|
||||
@Resource
|
||||
private CallWxpayFaceService callWxpayFaceService;
|
||||
|
||||
@Resource
|
||||
private WeChatPayFaceService weChatPayFaceService;
|
||||
|
||||
/**
|
||||
* 1 程序启动时初始化 :程序启动时初始化initWxpayface
|
||||
* @return
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
@RequestMapping(value = "/initWxpayface", method = RequestMethod.POST)
|
||||
public Result<WxFacePayResp> initWxpayface() throws JsonProcessingException, UnsupportedEncodingException, WxpayFaceSDKDll.DllRegistrationException {
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("initWxpayface","1",System.currentTimeMillis()/1000);
|
||||
WxFacePayResp wxFacePayResp = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
|
||||
System.out.println("**************1、程序启动时初始化:"+wxFacePayResp.toString());
|
||||
return Result.ok(wxFacePayResp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 2 获取数据getWxpayfaceRawdata
|
||||
* @return
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
@RequestMapping(value = "/getWxpayfaceRawdata", method = RequestMethod.POST)
|
||||
public Result<WxFacePayResp> getWxpayfaceRawdata() throws JsonProcessingException, UnsupportedEncodingException, WxpayFaceSDKDll.DllRegistrationException {
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceRawdata","1",System.currentTimeMillis()/1000);
|
||||
WxFacePayResp wxFacePayResp = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
|
||||
System.out.println("**************2、获取数据:"+wxFacePayResp.toString());
|
||||
|
||||
|
||||
|
||||
String rawdata = wxFacePayResp.getRawdata();
|
||||
return Result.ok(wxFacePayResp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证get_wxpayface_authinfo(rawdata)(获取调用凭证)
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(value = "/getWxpayfaceAuthinfo", method = RequestMethod.POST)
|
||||
public Result<Map<String, Object>> getWxpayfaceAuthinfo() throws Exception {
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceRawdata","1",System.currentTimeMillis()/1000);
|
||||
WxFacePayResp wxFacePayResp1 = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
|
||||
System.out.println("**************2、获取数据返回值:"+wxFacePayResp1.toString());
|
||||
String rawdata = wxFacePayResp1.getRawdata();
|
||||
|
||||
// 构建请求参数的JSON字符串
|
||||
Map<String, Object> wxFacePayResp = weChatPayFaceService.getWxFaceAuthInfoReqMap(rawdata);
|
||||
System.out.println("**************333:"+wxFacePayResp.toString());
|
||||
return Result.ok(wxFacePayResp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别getWxpayfaceCode(获取支付凭证)
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(value = "/getWxpayfaceCode", method = RequestMethod.POST)
|
||||
public Result<WxFacePayAuthinfoResp> getWxpayfaceCode() throws Exception {
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceCode","1",System.currentTimeMillis()/1000);
|
||||
|
||||
WxFacePayAuthinfoResp authinfoResp = weChatPayFaceService.doWxPayMethod(wxFacePayReq);
|
||||
System.out.println("**************4、进行人脸识别:"+authinfoResp.toString());
|
||||
|
||||
return Result.ok(authinfoResp);
|
||||
}
|
||||
|
||||
//5、进行发起订单支付
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
//微信配置
|
||||
CallWxpayFaceService callWxpayFaceService = new CallWxpayFaceServiceImpl();
|
||||
WeChatPayFaceService weChatPayFaceService = new WeChatPayFaceServiceImpl();
|
||||
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("initWxpayface","1",System.currentTimeMillis()/1000);
|
||||
WxFacePayResp wxFacePayResp = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
|
||||
System.out.println("**************1、程序启动时初始化:"+wxFacePayResp.toString());
|
||||
}
|
||||
|
||||
|
||||
//可以打印 JDK 中的 Provider 列表,以及所有签名算法
|
||||
public void outProvider() {
|
||||
TreeSet<String> algorithms = new TreeSet<>();
|
||||
|
||||
Provider[] providers = Security.getProviders();
|
||||
System.out.println("-----Provider 列表如下:-----");
|
||||
for (Provider provider : providers) {
|
||||
System.out.println(provider.getName());
|
||||
}
|
||||
|
||||
System.out.println("-----支持的签名算法如下:-----");
|
||||
|
||||
for (Provider provider : providers) {
|
||||
for (Provider.Service service : provider.getServices())
|
||||
if (service.getType().equals("Signature")) {
|
||||
algorithms.add(service.getAlgorithm());
|
||||
}
|
||||
}
|
||||
|
||||
for (String algorithm : algorithms) {
|
||||
System.out.println(algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package com.dpkj.modules.scanface.wx.dll;
|
||||
|
||||
import com.dpkj.modules.scanface.ali.dll.AliScanFaceDll;
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: Zhangxue
|
||||
* @time: 2025/4/17 17:02
|
||||
*/
|
||||
@Slf4j
|
||||
public class WxpayFaceSDKDll {
|
||||
private static final String DLL_NAME = "WxpayFaceSDK.dll"; // 确保文件名与实际资源一致
|
||||
//win32-x86-64/WxpayFaceSDK.dll
|
||||
private static final String RESOURCE_PATH = "win32-x86-64/" + DLL_NAME; // 例如: resources/native/WxpayFaceSDK.dll
|
||||
private static volatile boolean dllLoaded = false;
|
||||
|
||||
static {
|
||||
loadDllFromResources();
|
||||
}
|
||||
|
||||
|
||||
private static void loadDllFromResources() {
|
||||
if (dllLoaded) return;
|
||||
|
||||
try {
|
||||
// 从 resources 中读取 DLL 文件流
|
||||
InputStream inputStream = WxpayFaceSDKDll.class.getClassLoader().getResourceAsStream(RESOURCE_PATH);
|
||||
if (inputStream == null) {
|
||||
throw new RuntimeException("DLL 未找到: " + RESOURCE_PATH);
|
||||
}
|
||||
|
||||
// 创建临时目录并提取 DLL
|
||||
Path tempDir = Files.createTempDirectory("native-libs");
|
||||
Path tempDll = tempDir.resolve(DLL_NAME);
|
||||
Files.copy(inputStream, tempDll, StandardCopyOption.REPLACE_EXISTING);
|
||||
inputStream.close();
|
||||
|
||||
// 显式加载 DLL
|
||||
System.load(tempDll.toAbsolutePath().toString());
|
||||
dllLoaded = true;
|
||||
|
||||
// 可选:JVM 退出时清理临时文件
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
try {
|
||||
Files.deleteIfExists(tempDll);
|
||||
Files.deleteIfExists(tempDir);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("加载 DLL 失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dll instance() throws DllRegistrationException {
|
||||
try {
|
||||
// 加载已提取的 DLL
|
||||
return Native.load(DLL_NAME, Dll.class);
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
log.error("[WxpayFaceSDK][instance] 加载失败", e);
|
||||
throw new DllRegistrationException("Failed to load WxpayFaceSDK library: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义自定义异常类,用于表示注册控件时发生的错误
|
||||
*/
|
||||
public static class DllRegistrationException extends Exception {
|
||||
public DllRegistrationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DllRegistrationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义接口映射本地库中的函数。
|
||||
*/
|
||||
public interface Dll extends Library {
|
||||
/**
|
||||
* 调用人脸服务
|
||||
* 注意:这里的方法签名需要与DLL中的C函数签名一致
|
||||
* req和resp都是JSON字符串,需要转换为Pointer类型
|
||||
* char * -->String; char ** -->String[]
|
||||
* int -->int; int* --> IntByReference
|
||||
* @param reqBuf 请求参数(JSON字符串)
|
||||
* @param reqSize 请求参数长度
|
||||
* @param pRespBuf 用来接收响应结果(JSON字符串)的char**指针
|
||||
* @param pRespSize 用来接收响应结果长度的unsigned int*指针
|
||||
* @return 如果成功返回0,失败则返回非0
|
||||
*/
|
||||
//int wxpayCallFaceService(String reqBuf, int reqSize, String[] pRespBuf, IntByReference pRespSize);
|
||||
int wxpayCallFaceService(String reqBuf, int reqSize, long[] pRespBuf, int[] pRespSize);
|
||||
|
||||
|
||||
/**
|
||||
* char ** -->String[]
|
||||
* 释放人脸服务的响应字符串,调用wxpayCallFaceService成功后务必调用此函数释放内存
|
||||
* @param pRespBuf 指向响应结果(JSON字符串)的指针
|
||||
*/
|
||||
void wxpayReleaseResponse(String[] pRespBuf);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.dpkj.modules.scanface.wx.dll;
|
||||
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: Zhangxue
|
||||
* @time: 2025/4/17 17:02
|
||||
*/
|
||||
@Slf4j
|
||||
public class WxpayFaceSDKDll_old {
|
||||
|
||||
/**
|
||||
* 获取 Dll 实例,同时注册 Dll 控件。
|
||||
*
|
||||
* @return WxpayFaceSDKDll 实例
|
||||
* @throws WxpayFaceSDKDll_old.DllRegistrationException 如果注册控件失败,抛出此异常
|
||||
*/
|
||||
public static WxpayFaceSDKDll_old.Dll instance() throws DllRegistrationException {
|
||||
try {
|
||||
return Native.load("WxpayFaceSDK", WxpayFaceSDKDll_old.Dll.class);
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
log.info("[WxpayFaceSDK][instance][微信扫脸动态库] SDK注册失败:{}", e.getMessage());
|
||||
throw new WxpayFaceSDKDll_old.DllRegistrationException("Failed to load WxpayFaceSDK library: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义自定义异常类,用于表示注册控件时发生的错误
|
||||
*/
|
||||
public static class DllRegistrationException extends Exception {
|
||||
public DllRegistrationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DllRegistrationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义接口映射本地库中的函数。
|
||||
*/
|
||||
public interface Dll extends Library {
|
||||
/**
|
||||
* 调用人脸服务
|
||||
* 注意:这里的方法签名需要与DLL中的C函数签名一致
|
||||
* req和resp都是JSON字符串,需要转换为Pointer类型
|
||||
* char * -->String; char ** -->String[]
|
||||
* int -->int; int* --> IntByReference
|
||||
* @param reqBuf 请求参数(JSON字符串)
|
||||
* @param reqSize 请求参数长度
|
||||
* @param pRespBuf 用来接收响应结果(JSON字符串)的char**指针
|
||||
* @param pRespSize 用来接收响应结果长度的unsigned int*指针
|
||||
* @return 如果成功返回0,失败则返回非0
|
||||
*/
|
||||
//int wxpayCallFaceService(String reqBuf, int reqSize, String[] pRespBuf, IntByReference pRespSize);
|
||||
int wxpayCallFaceService(String reqBuf, int reqSize, long[] pRespBuf, int[] pRespSize);
|
||||
|
||||
|
||||
/**
|
||||
* char ** -->String[]
|
||||
* 释放人脸服务的响应字符串,调用wxpayCallFaceService成功后务必调用此函数释放内存
|
||||
* @param pRespBuf 指向响应结果(JSON字符串)的指针
|
||||
*/
|
||||
void wxpayReleaseResponse(String[] pRespBuf);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.dpkj.modules.scanface.wx.service;
|
||||
|
||||
import com.dpkj.modules.scanface.wx.dll.WxpayFaceSDKDll;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
|
||||
public interface CallWxpayFaceService {
|
||||
|
||||
/**
|
||||
* 调用SDK微信刷脸服务
|
||||
* @param reqJson
|
||||
* @param respJson
|
||||
* @return
|
||||
*/
|
||||
String callWxpayFaceService(String reqJson, List<String> respJson) throws UnsupportedEncodingException, WxpayFaceSDKDll.DllRegistrationException;
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.dpkj.modules.scanface.wx.service;
|
||||
|
||||
import com.dpkj.modules.scanface.wx.dll.WxpayFaceSDKDll;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayAuthinfoResp;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayReq;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayResp;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description: 调用微信刷脸方法
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/12/6 10:45
|
||||
*/
|
||||
public interface WeChatPayFaceService {
|
||||
|
||||
/**
|
||||
* 调用方法
|
||||
* 1、程序启动时初始化initWxpayface;2、获取数据getWxpayfaceRawdata;
|
||||
* @param wxFacePayReq
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
WxFacePayResp doWxPayIniMethod(WxFacePayReq wxFacePayReq) throws UnsupportedEncodingException, JsonProcessingException, WxpayFaceSDKDll.DllRegistrationException;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description: 3、获取调用凭证get_wxpayface_authinfo(rawdata)
|
||||
* @author: zhangxue
|
||||
* @date: 2024/12/4 14:35
|
||||
* @Param rawData 初始化数据。由微信人脸SDK的接口返回。
|
||||
* @return: java.util.Map<java.lang.String,java.lang.String>
|
||||
*/
|
||||
Map<String, Object> getWxFaceAuthInfoReqMap(String rawData) throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
* 调用方法
|
||||
* 4、进行人脸识别getWxpayfaceCode(获取支付凭证)
|
||||
* @param wxFacePayReq
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
WxFacePayAuthinfoResp doWxPayMethod(WxFacePayReq wxFacePayReq) throws UnsupportedEncodingException, JsonProcessingException, WxpayFaceSDKDll.DllRegistrationException;
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package com.dpkj.modules.scanface.wx.service.impl;
|
||||
|
||||
import com.dpkj.modules.scanface.wx.config.WxMpProperties;
|
||||
import com.dpkj.modules.scanface.wx.dll.WxpayFaceSDKDll;
|
||||
import com.dpkj.modules.scanface.wx.service.CallWxpayFaceService;
|
||||
import com.sun.jna.Memory;
|
||||
import com.sun.jna.Pointer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Security;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/11/28 10:04
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class CallWxpayFaceServiceImpl implements CallWxpayFaceService {
|
||||
//将 BouncyCastleProvider 添加到 Provider 列表中
|
||||
static {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
//赋值
|
||||
private static WxMpProperties wxMpProperties;
|
||||
public static void setWxMpConfiguration(WxMpProperties wxMpProperties) {
|
||||
CallWxpayFaceServiceImpl.wxMpProperties = wxMpProperties;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 调用SDK微信刷脸服务
|
||||
* @param reqJson
|
||||
* @param respJson
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String callWxpayFaceService(String reqJson, List<String> respJson) throws WxpayFaceSDKDll.DllRegistrationException {
|
||||
//组装请求数据
|
||||
Pointer reqPointer = new Memory(reqJson.length() + 1);
|
||||
reqPointer.setString(0, reqJson);
|
||||
//请求数据长度
|
||||
int reqSize = reqPointer.getString(0).length();
|
||||
System.out.println("-----------调用微信刷脸请求数据----------"+reqPointer.getString(0));
|
||||
|
||||
//接收响应
|
||||
long[] pRespBuf = new long[1];
|
||||
int[] respSize = new int[1];
|
||||
String resStr = new String();
|
||||
|
||||
|
||||
// 调用本地方法
|
||||
WxpayFaceSDKDll.Dll dll = WxpayFaceSDKDll.instance();
|
||||
int result =dll.wxpayCallFaceService(reqPointer.getString(0), reqSize, pRespBuf, respSize);
|
||||
if (result == 0) {
|
||||
Pointer pointer = new Pointer(pRespBuf[0]);
|
||||
byte[] byteArray = pointer.getByteArray(0, respSize[0]);
|
||||
resStr = new String(byteArray, StandardCharsets.UTF_8);
|
||||
|
||||
System.out.println("-----------调用服务成功结果: " + resStr);
|
||||
//释放
|
||||
dll.wxpayReleaseResponse(new String[2]);
|
||||
} else {
|
||||
Pointer pointer = new Pointer(pRespBuf[0]);
|
||||
byte[] byteArray = pointer.getByteArray(0, respSize[0]);
|
||||
resStr = new String(byteArray, StandardCharsets.UTF_8);
|
||||
System.err.println("-----------调用人脸服务失败: " +resStr);
|
||||
}
|
||||
return resStr;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,385 @@
|
|||
package com.dpkj.modules.scanface.wx.service.impl;
|
||||
|
||||
import com.dpkj.modules.scanface.ali.dll.AliScanFaceDll;
|
||||
import com.dpkj.modules.scanface.wx.config.WechatUrlConfig;
|
||||
import com.dpkj.modules.scanface.wx.config.WxMpProperties;
|
||||
import com.dpkj.modules.scanface.wx.dll.WxpayFaceSDKDll;
|
||||
import com.dpkj.modules.scanface.wx.service.CallWxpayFaceService;
|
||||
import com.dpkj.modules.scanface.wx.service.WeChatPayFaceService;
|
||||
import com.dpkj.modules.scanface.wx.util.WXPayUtil;
|
||||
import com.dpkj.modules.scanface.wx.util.WxRandomUtils;
|
||||
import com.dpkj.modules.scanface.wx.util.XmlUtils;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayAuthinfoResp;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayMicroPayResp;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayOrderResp;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayReq;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayResp;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.sun.jna.Memory;
|
||||
import com.sun.jna.Pointer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* @description: 调用微信刷脸方法
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/12/6 10:45
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
|
||||
@Autowired
|
||||
private CallWxpayFaceService callWxpayFaceService;
|
||||
|
||||
|
||||
//赋值
|
||||
private static WxMpProperties wxMpProperties;
|
||||
|
||||
public static void setWxMpConfiguration(WxMpProperties wxMpProperties) {
|
||||
WeChatPayFaceServiceImpl.wxMpProperties = wxMpProperties;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 调用方法
|
||||
* 1、程序启动时初始化initWxpayface;2、获取数据getWxpayfaceRawdata;
|
||||
*
|
||||
* @param wxFacePayReq
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
@Override
|
||||
public WxFacePayResp doWxPayIniMethod(WxFacePayReq wxFacePayReq) throws JsonProcessingException, WxpayFaceSDKDll.DllRegistrationException {
|
||||
// 构建请求参数的JSON字符串
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String reqJson = mapper.writeValueAsString(wxFacePayReq);
|
||||
|
||||
// 创建一个Pointer来接收响应
|
||||
//List<String> pResp= new ArrayList<>();
|
||||
//String result = callWxpayFaceService.callWxpayFaceService(req,pResp);
|
||||
|
||||
//组装请求数据
|
||||
Pointer reqPointer = new Memory(reqJson.length() + 1);
|
||||
reqPointer.setString(0, reqJson);
|
||||
//请求数据长度
|
||||
int reqSize = reqPointer.getString(0).length();
|
||||
System.out.println("-----------调用微信刷脸请求数据----------" + reqPointer.getString(0));
|
||||
|
||||
//接收响应
|
||||
long[] pRespBuf = new long[1];
|
||||
int[] respSize = new int[1];
|
||||
String resStr = new String();
|
||||
|
||||
|
||||
// 调用本地方法
|
||||
WxpayFaceSDKDll.Dll dll = WxpayFaceSDKDll.instance();
|
||||
int result = dll.wxpayCallFaceService(reqPointer.getString(0), reqSize, pRespBuf, respSize);
|
||||
log.info("[WeChatPayFaceServiceImpl][doWxPayIniMethod][95] DLL 返回码: {}", result);
|
||||
if (result == 0) {
|
||||
Pointer pointer = new Pointer(pRespBuf[0]);
|
||||
byte[] byteArray = pointer.getByteArray(0, respSize[0]);
|
||||
resStr = new String(byteArray, StandardCharsets.UTF_8);
|
||||
|
||||
System.out.println("-----------调用服务成功结果: " + resStr);
|
||||
//释放
|
||||
dll.wxpayReleaseResponse(new String[2]);
|
||||
} else {
|
||||
Pointer pointer = new Pointer(pRespBuf[0]);
|
||||
byte[] byteArray = pointer.getByteArray(0, respSize[0]);
|
||||
resStr = new String(byteArray, StandardCharsets.UTF_8);
|
||||
System.err.println("-----------调用人脸服务失败: " + resStr);
|
||||
}
|
||||
|
||||
//响应结果
|
||||
WxFacePayResp wxFacePayResp = mapper.readValue(resStr, WxFacePayResp.class);
|
||||
return wxFacePayResp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description: 3、获取调用凭证get_wxpayface_authinfo(rawdata)
|
||||
* @author: zhangxue
|
||||
* @date: 2024/12/4 14:35
|
||||
* @Param rawData 初始化数据。由微信人脸SDK的接口返回。
|
||||
* @return: java.util.Map<java.lang.String, java.lang.String>
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getWxFaceAuthInfoReqMap(String rawData) throws Exception {
|
||||
SortedMap<String, String> map = new TreeMap<String, String>();
|
||||
//门店编号, 由商户定义, 各门店唯一。
|
||||
map.put("store_id", "1111111111111");
|
||||
//门店名称,由商户定义。(可用于展示);中文会导致调用失败
|
||||
String text = "刷脸设备一号";
|
||||
String storeName = Base64.getEncoder().encodeToString(text.getBytes());
|
||||
map.put("store_name", storeName);
|
||||
//终端设备编号,由商户定义
|
||||
map.put("device_id", "test111");
|
||||
//初始化数据。由微信人脸SDK的接口返回。
|
||||
map.put("rawdata", rawData);
|
||||
//商户号绑定的公众号/小程序 appid
|
||||
map.put("appid", wxMpProperties.getMchConfig().getAppId());
|
||||
//商户号
|
||||
map.put("mch_id", wxMpProperties.getMchConfig().getMchId());
|
||||
//取当前时间,10位unix时间戳。
|
||||
long timeStampSec = System.currentTimeMillis() / 1000;
|
||||
String timestamp = String.format("%010d", timeStampSec);
|
||||
map.put("now", timestamp);
|
||||
//版本号。固定为1
|
||||
map.put("version", "1");
|
||||
//随机字符串,不长于32位:工具类微信随机数
|
||||
map.put("nonce_str", WxRandomUtils.getNonceStr());
|
||||
//参数签名,使用MD5
|
||||
map.put("sign_type", "MD5");
|
||||
|
||||
//加密和生成微信v2指定的xml格式
|
||||
// WXPayUtil.createSign("UTF-8",map,wxMpProperties.getMchConfig().getKeyApi());
|
||||
String sign = WXPayUtil.generateSignedXml(map, wxMpProperties.getMchConfig().getKeyApi(), WxPayConstants.SignType.MD5);
|
||||
log.info("--------构建微信获取刷脸授权XML参数:【{}】", sign);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
HttpEntity<String> stringHttpEntity = new HttpEntity<String>(sign, headers);
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
//发起http调用
|
||||
ResponseEntity<String> exchange = restTemplate.exchange(WechatUrlConfig.GET_WXPAYFACE_AUTHINFO,
|
||||
HttpMethod.POST,
|
||||
stringHttpEntity,
|
||||
String.class);
|
||||
log.info("--------发起http调用结果:【{}】", exchange.getBody());
|
||||
//转成map方便取值
|
||||
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
|
||||
//转成返回对象
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
WxFacePayAuthinfoResp wxFacePayAuthinfoResp = mapper.readValue(exchange.getBody(), WxFacePayAuthinfoResp.class);
|
||||
log.info("--------发起http调用结果转换", wxFacePayAuthinfoResp.toString());
|
||||
|
||||
return stringMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 调用方法
|
||||
* 4、进行人脸识别getWxpayfaceCode(获取支付凭证)
|
||||
*
|
||||
* @param wxFacePayReq
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
@Override
|
||||
public WxFacePayAuthinfoResp doWxPayMethod(WxFacePayReq wxFacePayReq) throws JsonProcessingException, UnsupportedEncodingException, WxpayFaceSDKDll.DllRegistrationException {
|
||||
// 构建请求参数的JSON字符串
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String req = mapper.writeValueAsString(wxFacePayReq);
|
||||
|
||||
// 创建一个Pointer来接收响应
|
||||
List<String> pResp = new ArrayList<>();
|
||||
String result = callWxpayFaceService.callWxpayFaceService(req, pResp);
|
||||
|
||||
//响应结果
|
||||
WxFacePayAuthinfoResp authinfoResp = mapper.readValue(result, WxFacePayAuthinfoResp.class);
|
||||
return authinfoResp;
|
||||
}
|
||||
|
||||
|
||||
//5、进行发起订单支付
|
||||
public Map<String, Object> createWxOrder() throws Exception {
|
||||
SortedMap<String, String> map = new TreeMap<String, String>();
|
||||
//微信分配的公众账号ID(企业号corpid即为此appId)
|
||||
map.put("appid", wxMpProperties.getMchConfig().getAppId());
|
||||
//商户号
|
||||
map.put("mch_id", wxMpProperties.getMchConfig().getMchId());
|
||||
//随机字符串,不长于32位:工具类微信随机数
|
||||
map.put("nonce_str", WxRandomUtils.getNonceStr());
|
||||
//签名, map.put("sign", "");
|
||||
//商品简单描述,
|
||||
map.put("body", "");
|
||||
//商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一
|
||||
map.put("out_trade_no", "");
|
||||
//Int 订单总金额,单位为分,只能为整数
|
||||
map.put("total_fee", "");
|
||||
//支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP
|
||||
map.put("spbill_create_ip", "");
|
||||
//扫码支付付款码,设备读取用户微信中的条码或者二维码信息
|
||||
map.put("auth_code", "");
|
||||
|
||||
//加密和生成微信v2指定的xml格式
|
||||
// WXPayUtil.createSign("UTF-8",map,wxMpProperties.getMchConfig().getKeyApi());
|
||||
String sign = WXPayUtil.generateSignedXml(map, wxMpProperties.getMchConfig().getKeyApi(), WxPayConstants.SignType.MD5);
|
||||
log.info("--------构建微信获取刷脸授权XML参数:【{}】", sign);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
HttpEntity<String> stringHttpEntity = new HttpEntity<String>(sign, headers);
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
//发起http调用
|
||||
ResponseEntity<String> exchange = restTemplate.exchange(WechatUrlConfig.CREATEORDER,
|
||||
HttpMethod.POST,
|
||||
stringHttpEntity,
|
||||
String.class);
|
||||
log.info("--------5、进行发起订单支付:发起http调用结果:【{}】", exchange.getBody());
|
||||
//转成map方便取值
|
||||
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
|
||||
//转成返回对象
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
WxFacePayMicroPayResp microPayResp = mapper.readValue(exchange.getBody(), WxFacePayMicroPayResp.class);
|
||||
log.info("--------5、进行发起订单支付,发起http调用结果转换", microPayResp.toString());
|
||||
|
||||
return stringMap;
|
||||
}
|
||||
|
||||
|
||||
//6、查询订单状态
|
||||
public Map<String, Object> orderquery() throws Exception {
|
||||
SortedMap<String, String> map = new TreeMap<String, String>();
|
||||
//微信支付分配的公众账号ID(企业号corpid即为此appId)
|
||||
map.put("appid", wxMpProperties.getMchConfig().getAppId());
|
||||
//微信支付分配的商户号
|
||||
map.put("mch_id", wxMpProperties.getMchConfig().getMchId());
|
||||
//微信的订单号,建议优先使用;必填:否
|
||||
map.put("transaction_id", "");
|
||||
//商户系统内部订单号;必填:否
|
||||
map.put("out_trade_no", "");
|
||||
//随机字符串,不长于32位:工具类微信随机数
|
||||
map.put("nonce_str", WxRandomUtils.getNonceStr());
|
||||
//参数签名,使用MD5
|
||||
map.put("sign_type", "MD5");
|
||||
//sign:通过签名算法计算得出的签名值
|
||||
String sign = WXPayUtil.generateSignedXml(map, wxMpProperties.getMchConfig().getKeyApi(), WxPayConstants.SignType.MD5);
|
||||
log.info("--------构建微信获取刷脸授权XML参数:【{}】", sign);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
HttpEntity<String> stringHttpEntity = new HttpEntity<String>("", headers);
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
//发起http调用
|
||||
ResponseEntity<String> exchange = restTemplate.exchange(WechatUrlConfig.ORDERQUERY,
|
||||
HttpMethod.POST,
|
||||
stringHttpEntity,
|
||||
String.class);
|
||||
log.info("--------6、查询订单状态,发起http调用结果:【{}】", exchange.getBody());
|
||||
//转成map方便取值
|
||||
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
|
||||
//转成返回对象
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
WxFacePayOrderResp orderResp = mapper.readValue(exchange.getBody(), WxFacePayOrderResp.class);
|
||||
log.info("--------6、查询订单状态,发起http调用结果转换", orderResp.toString());
|
||||
|
||||
return stringMap;
|
||||
}
|
||||
|
||||
|
||||
//7、撤销交易
|
||||
public Map<String, Object> reverse() throws Exception {
|
||||
SortedMap<String, String> map = new TreeMap<String, String>();
|
||||
//微信分配的公众账号ID(企业号corpid即为此appId)
|
||||
map.put("appid", wxMpProperties.getMchConfig().getAppId());
|
||||
//商户号
|
||||
map.put("mch_id", wxMpProperties.getMchConfig().getMchId());
|
||||
//微信的订单号,优先使用
|
||||
map.put("transaction_id", "");
|
||||
//商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no
|
||||
map.put("out_trade_no", "");
|
||||
//随机字符串,不长于32位。
|
||||
map.put("nonce_str", WxRandomUtils.getNonceStr());
|
||||
|
||||
//加密和生成微信v2指定的xml格式
|
||||
String sign = WXPayUtil.generateSignedXml(map, wxMpProperties.getMchConfig().getKeyApi(), WxPayConstants.SignType.MD5);
|
||||
log.info("--------构建微信XML参数:【{}】", sign);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
HttpEntity<String> stringHttpEntity = new HttpEntity<String>("", headers);
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
//发起http调用
|
||||
ResponseEntity<String> exchange = restTemplate.exchange(WechatUrlConfig.REVERSE,
|
||||
HttpMethod.POST,
|
||||
stringHttpEntity,
|
||||
String.class);
|
||||
log.info("--------7、撤销交易,发起http调用结果:【{}】", exchange.getBody());
|
||||
//转成map方便取值
|
||||
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
|
||||
//转成返回对象
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
WxFacePayOrderResp orderResp = mapper.readValue(exchange.getBody(), WxFacePayOrderResp.class);
|
||||
log.info("--------7、撤销交易,发起http调用结果转换", orderResp.toString());
|
||||
|
||||
return stringMap;
|
||||
}
|
||||
|
||||
|
||||
//8、更新支付结果:通知人脸SDK更新支付结果
|
||||
public WxFacePayResp updateWxpayfacePayResult(String storeId, String authInfo, String payresult) throws Exception {
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("updateWxpayfacePayResult", "1", System.currentTimeMillis() / 1000);
|
||||
//微信分配的公众账号ID(企业号corpid即为此appId)
|
||||
wxFacePayReq.setAppid(wxMpProperties.getMchConfig().getAppId());
|
||||
//商户号
|
||||
wxFacePayReq.setMch_id(wxMpProperties.getMchConfig().getMchId());
|
||||
//门店编号
|
||||
wxFacePayReq.setStore_id(storeId);
|
||||
//调用凭证
|
||||
wxFacePayReq.setAuthinfo(authInfo);
|
||||
//支付结果。可取值:SUCCESS: 支付成功、ERROR: 支付失败
|
||||
wxFacePayReq.setPayresult(payresult);
|
||||
|
||||
// 构建请求参数的JSON字符串
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String req = mapper.writeValueAsString(wxFacePayReq);
|
||||
|
||||
// 创建一个Pointer来接收响应
|
||||
List<String> pResp = new ArrayList<>();
|
||||
String result = callWxpayFaceService.callWxpayFaceService(req, pResp);
|
||||
|
||||
//响应结果
|
||||
WxFacePayResp authinfoResp = mapper.readValue(result, WxFacePayResp.class);
|
||||
return authinfoResp;
|
||||
}
|
||||
|
||||
|
||||
//9、停止刷脸支付
|
||||
public WxFacePayResp stopWxpayface(String storeId, String authInfo, String payresult) throws Exception {
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("stopWxpayface", "1", System.currentTimeMillis() / 1000);
|
||||
//微信分配的公众账号ID(企业号corpid即为此appId)
|
||||
wxFacePayReq.setAppid(wxMpProperties.getMchConfig().getAppId());
|
||||
//商户号
|
||||
wxFacePayReq.setMch_id(wxMpProperties.getMchConfig().getMchId());
|
||||
//调用凭证
|
||||
wxFacePayReq.setAuthinfo(authInfo);
|
||||
|
||||
// 构建请求参数的JSON字符串
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String req = mapper.writeValueAsString(wxFacePayReq);
|
||||
|
||||
// 创建一个Pointer来接收响应
|
||||
List<String> pResp = new ArrayList<>();
|
||||
String result = callWxpayFaceService.callWxpayFaceService(req, pResp);
|
||||
|
||||
//响应结果
|
||||
WxFacePayResp authinfoResp = mapper.readValue(result, WxFacePayResp.class);
|
||||
return authinfoResp;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.dpkj.modules.scanface.wx.util;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* @description: MD5工具类
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/12/5 11:34
|
||||
*/
|
||||
public class MD5Util {
|
||||
|
||||
private static String byteArrayToHexString(byte b[]) {
|
||||
StringBuffer resultSb = new StringBuffer();
|
||||
for (int i = 0; i < b.length; i++)
|
||||
resultSb.append(byteToHexString(b[i]));
|
||||
|
||||
return resultSb.toString();
|
||||
}
|
||||
|
||||
private static String byteToHexString(byte b) {
|
||||
int n = b;
|
||||
if (n < 0)
|
||||
n += 256;
|
||||
int d1 = n / 16;
|
||||
int d2 = n % 16;
|
||||
return hexDigits[d1] + hexDigits[d2];
|
||||
}
|
||||
|
||||
public static String MD5Encode(String origin, String charsetname) {
|
||||
String resultString = null;
|
||||
try {
|
||||
resultString = new String(origin);
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
if (charsetname == null || "".equals(charsetname))
|
||||
resultString = byteArrayToHexString(md.digest(resultString
|
||||
.getBytes()));
|
||||
else
|
||||
resultString = byteArrayToHexString(md.digest(resultString
|
||||
.getBytes(charsetname)));
|
||||
} catch (Exception exception) {
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
|
||||
private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
|
||||
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
|
||||
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package com.dpkj.modules.scanface.wx.util;
|
||||
|
||||
import org.jdom2.Content;
|
||||
import org.jdom2.Document;
|
||||
import org.jdom2.Element;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* @description: 生成签名
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/12/4 14:27
|
||||
*/
|
||||
public class WXPayUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 生成微信API请求的MD5签名,并返回XML格式的字符串
|
||||
*
|
||||
* @param params 参数Map
|
||||
* @param apiKey 微信API密钥
|
||||
* @return 微信v2指定的XML格式字符串
|
||||
*/
|
||||
public static String generateSignedXml(Map<String, String> params, String apiKey,String signType) {
|
||||
// 将参数Map按照key的字典顺序排序
|
||||
Map<String, String> sortedParams = new TreeMap<>(params);
|
||||
|
||||
// 构建签名原文
|
||||
StringBuilder signSrc = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
|
||||
if (!"sign".equals(entry.getKey())) {
|
||||
signSrc.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
|
||||
}
|
||||
}
|
||||
signSrc.append("key=").append(apiKey);
|
||||
|
||||
// 计算MD5签名
|
||||
String sign = getMD5(signSrc.toString(),signType).toUpperCase();
|
||||
|
||||
// 构建XML格式的字符串
|
||||
StringBuilder xmlBuilder = new StringBuilder();
|
||||
xmlBuilder.append("<xml>");
|
||||
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
|
||||
xmlBuilder.append("<").append(entry.getKey()).append(">").append(entry.getValue()).append("</").append(entry.getKey()).append(">");
|
||||
}
|
||||
xmlBuilder.append("<sign><![CDATA[").append(sign).append("]]></sign>");
|
||||
xmlBuilder.append("</xml>");
|
||||
|
||||
return xmlBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用MD5算法计算字符串的签名
|
||||
*
|
||||
* @param input 输入字符串
|
||||
* @return MD5签名字符串
|
||||
*/
|
||||
private static String getMD5(String input,String signType) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance(signType);
|
||||
byte[] digest = md.digest(input.getBytes());
|
||||
return DatatypeConverter.printHexBinary(digest).toLowerCase();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("MD5算法不支持", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, String> xmlToMap(String xml) throws Exception {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
Document document = new Document((List<? extends Content>) new StringReader(xml));
|
||||
Element root = document.getRootElement();
|
||||
|
||||
for (Element child : root.getChildren()) {
|
||||
map.put(child.getName(), child.getText());
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
//定义签名,微信根据参数字段的ASCII码值进行排序 加密签名,故使用SortMap进行参数排序
|
||||
public static String createSign(String characterEncoding, SortedMap<String,String> parameters,String key){
|
||||
StringBuffer sb = new StringBuffer();
|
||||
Set es = parameters.entrySet();
|
||||
Iterator it = es.iterator();
|
||||
while(it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry)it.next();
|
||||
String k = (String)entry.getKey();
|
||||
Object v = entry.getValue();
|
||||
if(null != v && !"".equals(v)
|
||||
&& !"sign".equals(k) && !"key".equals(k)) {
|
||||
sb.append(k + "=" + v + "&");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("key=" + key);//最后加密时添加商户密钥,由于key值放在最后,所以不用添加到SortMap里面去,单独处理,编码方式采用UTF-8
|
||||
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
|
||||
return sign;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.dpkj.modules.scanface.wx.util;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
|
||||
public class WxRandomUtils {
|
||||
|
||||
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
private static final Random RANDOM = new SecureRandom();
|
||||
|
||||
|
||||
/**
|
||||
* 获取随机字符串 Nonce Str
|
||||
*
|
||||
* @return String 随机字符串
|
||||
*/
|
||||
public static String getNonceStr() {
|
||||
char[] nonceChars = new char[32];
|
||||
for (int index = 0; index < nonceChars.length; ++index) {
|
||||
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
|
||||
}
|
||||
return new String(nonceChars);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接参数
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
private static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
|
||||
return appId + "\n"
|
||||
+ timestamp + "\n"
|
||||
+ nonceStr + "\n"
|
||||
+ packag + "\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.dpkj.modules.scanface.wx.util;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dom4j.Attribute;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
/**
|
||||
* @description: xml解析为Map
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/12/5 11:42
|
||||
*/
|
||||
public class XmlUtils {
|
||||
|
||||
/**
|
||||
* xml解析器
|
||||
*
|
||||
* @param xml xml字符串
|
||||
* @param filterRootEleName 匹配的根节点名
|
||||
* @return
|
||||
* @返回map,格式:键:值
|
||||
* @返回属性值:->节点名=>属性名:属性值
|
||||
* @返回节点值:->节点名:值
|
||||
* @返回子节点属性值:->节点名->子节点名=>属性名:属性值
|
||||
* @返回子节点值:->节点名->子节点名:属性值
|
||||
*/
|
||||
public static Map<String, Object> xmlParser(String xml, String filterRootEleName) {
|
||||
Map<String, Object> retMap = new HashMap<>();
|
||||
//1.创建Reader对象
|
||||
try {
|
||||
SAXReader reader = new SAXReader();
|
||||
InputStream targetStream = IOUtils.toInputStream(xml, StandardCharsets.UTF_8.name());
|
||||
Document document = reader.read(targetStream);
|
||||
//3.获取根节点
|
||||
Element rootElement = document.getRootElement();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
parser(rootElement, builder, filterRootEleName, retMap);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return retMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* xml递归解析器
|
||||
*
|
||||
* @param ele 解析节点
|
||||
* @param eleKey 上级节点key
|
||||
* @param retMap 返回map
|
||||
*/
|
||||
private static void parser(Element ele, StringBuilder eleKey, String firstEleName, Map<String, Object> retMap) {
|
||||
StringBuilder builder = new StringBuilder(eleKey.toString());
|
||||
if (StringUtils.isEmpty(firstEleName)
|
||||
|| firstEleName.equals(ele.getName())) {
|
||||
firstEleName = null;
|
||||
builder.append("->" + ele.getName());
|
||||
if (org.apache.commons.lang3.StringUtils.isNotEmpty(org.apache.commons.lang3.StringUtils.stripToEmpty(ele.getData() + ""))) {
|
||||
retMap.put(builder.toString(), org.apache.commons.lang3.StringUtils.stripToEmpty(ele.getData() + ""));
|
||||
}
|
||||
List<Attribute> attributes = ele.attributes();
|
||||
for (Attribute attribute : attributes) {
|
||||
StringBuilder builder1 = new StringBuilder(builder.toString());
|
||||
builder1.append("=>" + attribute.getName());
|
||||
if (StringUtils.isNotEmpty(attribute.getValue())) {
|
||||
retMap.put(builder1.toString(), attribute.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
Iterator iterator1 = ele.elementIterator();
|
||||
while (iterator1.hasNext()) {
|
||||
Element eleChild = (Element) iterator1.next();
|
||||
parser(eleChild, builder, firstEleName, retMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.dpkj.modules.scanface.wx.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description: 硬件提供参数
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/11/28 10:01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class WxFaceAuthInfoReq {
|
||||
|
||||
private String deviceId;
|
||||
|
||||
private Map<String,String> rawData;
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package com.dpkj.modules.scanface.wx.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @description: 3、获取调用凭证返回值
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/12/6 9:23
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class WxFacePayAuthinfoResp {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private String return_code;
|
||||
|
||||
/**
|
||||
* 对错误码的描述
|
||||
*/
|
||||
private String return_msg;
|
||||
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 初始化数据。用于接口调用获取authinfo
|
||||
*/
|
||||
private String rawdata;
|
||||
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证
|
||||
* 必填:是
|
||||
* SDK调用凭证。用于调用SDK的人脸识别接口。
|
||||
*/
|
||||
private String authinfo;
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证
|
||||
* 必填:否
|
||||
* authinfo的有效时间, 单位秒。
|
||||
*/
|
||||
private int expires_in;
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证
|
||||
* 必填:是
|
||||
* 随机字符串
|
||||
*/
|
||||
private String nonce_str;
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证
|
||||
* 必填:是
|
||||
* 响应结果签名
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证
|
||||
* 必填:是
|
||||
* 公众号
|
||||
*/
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证
|
||||
* 必填:否
|
||||
* 商户号
|
||||
*/
|
||||
private String mch_id;
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证
|
||||
* 必填:否
|
||||
* 子商户公众账号ID(服务商模式)
|
||||
*/
|
||||
private String sub_appid;
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证
|
||||
* 必填:是
|
||||
* 子商户号(服务商模式)
|
||||
*/
|
||||
private String sub_mch_id;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 是否必填:S
|
||||
* 人脸凭证, 用于刷脸支付。
|
||||
*/
|
||||
private String face_code;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 是否必填:S
|
||||
* openid
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 是否必填:否
|
||||
* 子商户号下的openid(服务商模式)
|
||||
*/
|
||||
private String sub_openid;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 是否必填:否
|
||||
* 用户身份信息查询凭证
|
||||
*/
|
||||
private String face_sid;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package com.dpkj.modules.scanface.wx.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @description: 5、进行发起订单支付 返回值
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/12/6 9:23
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class WxFacePayMicroPayResp extends WxFacePayOrderResp{
|
||||
|
||||
/************当return_code 和result_code都为SUCCESS的时,还会包括以下字段:*******************/
|
||||
|
||||
/**
|
||||
* 用户在商户appid 下的唯一标识
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 用户是否关注公众账号,仅在公众账号类型支付有效,取值范围:Y或N;Y-关注;N-未关注
|
||||
*/
|
||||
private String is_subscribe;
|
||||
|
||||
/**
|
||||
* MICROPAY 付款码支付
|
||||
*/
|
||||
private String trade_type;
|
||||
|
||||
/**
|
||||
* 银行类型,采用字符串类型的银行标识
|
||||
*/
|
||||
private String bank_type;
|
||||
|
||||
/**
|
||||
* 符合ISO 4217标准的三位字母代码,默认人民币:CNY
|
||||
*/
|
||||
private String fee_type;
|
||||
|
||||
/**
|
||||
* 订单总金额,单位为分,只能为整数
|
||||
*/
|
||||
private Integer total_fee;
|
||||
|
||||
/**
|
||||
* 当订单使用了免充值型优惠券后返回该参数,应结订单金额=订单金额-免充值优惠券金额。
|
||||
*/
|
||||
private Integer settlement_total_fee;
|
||||
|
||||
/**
|
||||
* “代金券”金额<=订单金额,订单金额-“代金券”金额=现金支付金额,
|
||||
*/
|
||||
private Integer coupon_fee;
|
||||
|
||||
/**
|
||||
* 符合ISO 4217标准的三位字母代码,默认人民币:CNY,
|
||||
*/
|
||||
private String cash_fee_type;
|
||||
|
||||
/**
|
||||
* 订单现金支付金额,
|
||||
*/
|
||||
private Integer cash_fee;
|
||||
|
||||
/**
|
||||
* 微信支付订单号
|
||||
*/
|
||||
private String transaction_id;
|
||||
|
||||
/**
|
||||
* 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。
|
||||
*/
|
||||
private String out_trade_no;
|
||||
|
||||
/**
|
||||
* 商家数据包,原样返回
|
||||
*/
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 订单生成时间,格式为yyyyMMddHHmmss
|
||||
*/
|
||||
private String time_end;
|
||||
|
||||
/**
|
||||
* 新增返回,单品优惠功能字段
|
||||
*/
|
||||
private String promotion_detail;
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
package com.dpkj.modules.scanface.wx.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @description: 5、进行发起订单支付 返回值;6、查询订单状态
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/12/10 15:30
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class WxFacePayOrderResp {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
* 文档:https://pay.weixin.qq.com/wiki/doc/wxfacepay/develop/windows/facepay.html#_5%E3%80%81%E8%BF%9B%E8%A1%8C%E5%8F%91%E8%B5%B7%E8%AE%A2%E5%8D%95%E6%94%AF%E4%BB%98
|
||||
*/
|
||||
private String return_code;
|
||||
|
||||
/**
|
||||
* 对错误码的描述
|
||||
*/
|
||||
private String return_msg;
|
||||
|
||||
/**
|
||||
* 调用接口提交的公众账号ID
|
||||
*/
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 调用接口提交的商户号
|
||||
*/
|
||||
private String mch_id;
|
||||
|
||||
/**
|
||||
* 调用接口提交的终端设备号,
|
||||
*/
|
||||
private String device_info;
|
||||
|
||||
/**
|
||||
* 微信返回的随机字符串,
|
||||
*/
|
||||
private String nonce_str;
|
||||
|
||||
/**
|
||||
* 微信返回的签名,
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* SUCCESS/FAIL
|
||||
*/
|
||||
private String result_code;
|
||||
|
||||
/**
|
||||
* 详细参见错误列表
|
||||
*/
|
||||
private String err_code;
|
||||
|
||||
/**
|
||||
* 错误返回的信息描述
|
||||
*/
|
||||
private String err_code_des;
|
||||
|
||||
/**
|
||||
* SUCCESS—支付成功,
|
||||
* REFUND—转入退款当result_code为FAIL时返回错误代码,
|
||||
* NOTPAY—未支付当result_code为FAIL时返回错误描述,
|
||||
* CLOSED—已关闭,REVOKED—已撤销(付款码支付),
|
||||
* USERPAYING--用户支付中(付款码支付),
|
||||
* PAYERROR--支付失败(其他原因,如银行返回失败),
|
||||
*/
|
||||
private String trade_state;
|
||||
|
||||
/**
|
||||
* 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
|
||||
*/
|
||||
private String out_trade_no;
|
||||
|
||||
/**
|
||||
* 附加数据,原样返回
|
||||
*/
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 用户在商户appid下的唯一标识
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 用户是否关注公众账号,Y-关注,N-未关注
|
||||
*/
|
||||
private String is_subscribe;
|
||||
|
||||
/**
|
||||
* 调用接口提交的交易类型,取值如下:JSAPI,NATIVE,APP,MICROPAY
|
||||
*/
|
||||
private String trade_type;
|
||||
|
||||
/**
|
||||
* 银行类型,采用字符串类型的银行标识
|
||||
*/
|
||||
private String bank_type;
|
||||
|
||||
/**
|
||||
* 订单总金额,单位为分
|
||||
*/
|
||||
private Integer total_fee;
|
||||
|
||||
/**
|
||||
* 现金支付金额订单现金支付金额
|
||||
*/
|
||||
private Integer cash_fee;
|
||||
|
||||
/**
|
||||
* 微信支付订单号
|
||||
*/
|
||||
private String transaction_id;
|
||||
|
||||
/**
|
||||
* 订单支付时间,格式为yyyyMMddHHmmss,如20091225091010
|
||||
*/
|
||||
private String time_end;
|
||||
|
||||
/**
|
||||
* 对当前查询订单状态的描述和下一步操作的指引
|
||||
*/
|
||||
private int trade_state_desc;
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package com.dpkj.modules.scanface.wx.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @description:WxFacePayReq
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/11/29 17:18
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class WxFacePayReq {
|
||||
|
||||
/**
|
||||
* 命令字,即各接口名:
|
||||
* initWxpayface
|
||||
* getWxpayfaceRawdata
|
||||
* getWxpayfaceCode
|
||||
* releaseWxpayface
|
||||
*/
|
||||
private String cmd;
|
||||
|
||||
/**
|
||||
* 版本号, 固定填写1
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 取当前时间的10位unix时间戮
|
||||
*/
|
||||
private long now;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:是
|
||||
* 商户号绑定的公众号/小程序 appid
|
||||
*/
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:是
|
||||
* 商户号
|
||||
*/
|
||||
private String mch_id;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 子商户绑定的公众号/小程序 appid(可不填)
|
||||
*/
|
||||
private String sub_appid;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 子商户号(非服务商模式不填)
|
||||
*/
|
||||
private String sub_mch_id;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:是
|
||||
* 门店编号
|
||||
*/
|
||||
private String store_id;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 通过getWxpayfaceUserInfo获取的openid,传入后可使用快捷支付模式。1.24版本以上支持该参数
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 目标face_code类型,可选值:"1",刷卡付款码:18位数字,通过「付款码支付/被扫支付」接口完成支付,
|
||||
* 如果不填写则默认为"0",人脸付款码:数字字母混合,通过「刷脸支付」接口完成支付。1.16版本以上支持该参数
|
||||
*/
|
||||
private String face_code_type;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 订单金额(数字), 单位分,该字段在在face_code_type为"1"时可不填,为"0"时必填
|
||||
*/
|
||||
private String total_fee;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 商户订单号,须与调用支付接口时字段一致,该字段在在face_code_type为"1"时可不填,为"0"时必填
|
||||
*/
|
||||
private String out_trade_no;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:是
|
||||
* FACEPAY: 人脸凭证(face_code),用于刷脸支付 FACE_AUTH: 实名认证(需联系微信支付开通权限)
|
||||
*/
|
||||
private String face_authtype;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:是
|
||||
* 调用凭证
|
||||
*/
|
||||
private String authinfo;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 指定刷脸界面显示的屏幕编号。
|
||||
* 编号1为主屏幕,其余屏幕按系统设置中的顺序从2开始编号,常用场景举例:双屏机器上传"2"即可显示在副屏上。如果不填写则默认显示在主屏幕。1.18版本以上支持该参数
|
||||
*/
|
||||
private String screen_index;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 设置不接受外接键盘输入,可选值:"1",禁用。1.23版本以上支持该参数
|
||||
*/
|
||||
private String disable_keyboard;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 设置刷脸窗口以无焦点方式启动,可选值:"1",无焦点启动窗口。1.26版本以上支持该参数
|
||||
*/
|
||||
private String use_window_nofocus;
|
||||
|
||||
|
||||
/**
|
||||
* 8、更新支付结果
|
||||
* 支付结果。可取值:SUCCESS: 支付成功、ERROR: 支付失败
|
||||
*/
|
||||
private String payresult;
|
||||
|
||||
|
||||
|
||||
//构建
|
||||
public WxFacePayReq(String cmd, String version, long now) {
|
||||
this.cmd= cmd;
|
||||
this.version =version;
|
||||
this.now = now;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.dpkj.modules.scanface.wx.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @description:WxFacePayResp 调用微信刷脸的返回值
|
||||
* @author: Zhangxue
|
||||
* @time: 2024/11/29 17:18
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class WxFacePayResp {
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private String return_code;
|
||||
|
||||
/**
|
||||
* 对错误码的描述
|
||||
*/
|
||||
private String return_msg;
|
||||
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 2、获取数据
|
||||
* 初始化数据。用于接口调用获取authinfo
|
||||
*/
|
||||
private String rawdata;
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue