微信刷脸

This commit is contained in:
2025-05-30 17:39:03 +08:00
parent 9c08c6e7d4
commit 7fc9839038
12 changed files with 834 additions and 112 deletions

View File

@@ -0,0 +1,42 @@
package com.dpkj.common.constant;
/**
* @description:
* @author: Zhangxue
* @time: 2025/5/28 11:04
*/
public interface WxConstant {
/**
* 门店编号, 由商户定义, 各门店唯一。
* TODO 修改
*/
String STORE_ID = "1111111111111";
//门店名称,由商户定义。(可用于展示);中文会导致调用失败
String STORE_TEXT = "device8998No1";
//终端设备编号,由商户定义
String DEVICE_ID = "device8998";
//版本号。固定为1
String VERSION = "1";
//参数签名,使用MD5
String SING_TYPE = "MD5";
/**
* 支付类型
*/
String FACEPAY = "FACEPAY";
/**
* 结果状态 成功
*/
String STATE_SUCCESS = "SUCCESS";
/**
* 结果状态 失败
*/
String STATE_FAIL = "FAIL";
}

View File

@@ -0,0 +1,467 @@
package com.dpkj.modules.scanface.wx.controller;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dpkj.common.constant.WxConstant;
import com.dpkj.common.vo.Result;
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.vo.WxFaceOrderVo;
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 com.fasterxml.jackson.databind.ObjectMapper;
import com.github.binarywang.wxpay.bean.request.WxPayOrderReverseRequest;
import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderReverseResult;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
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.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* @description: 微信刷脸支付
* @author: Zhangxue
* @time: 2025/5/28 14:20
*/
@Slf4j
@RestController
@RequestMapping("/wxpayFace")
public class WxFacePayController {
@Resource
private CallWxpayFaceService callWxpayFaceService;
@Resource
private WeChatPayFaceService weChatPayFaceService;
@Value("${dpkj.serverurl}")
private String serverUrl;
//赋值
@Autowired
private WxMpProperties wxMpProperties;
/**
* 调用整个刷脸的完整流程
*
* @param wxFaceOrderVo
* @return
* @throws Exception
*/
@RequestMapping(value = "/doFacePay", method = RequestMethod.POST)
public Result<WxFacePayAuthinfoResp> doFacePay(@RequestBody WxFaceOrderVo wxFaceOrderVo) throws Exception {
//1 初始化
this.initWxpayface();
//2 获取数据getWxpayfaceRawdata
WxFacePayResp wxFacePayResp = this.getWxpayfaceRawdata();
//String rawdata = wxFacePayResp.getRawdata();
//3、获取调用凭证get_wxpayface_authinfo(rawdata)(获取调用凭证)
WxFacePayAuthinfoResp wxFacePayResp0 = this.getWxpayfaceAuthinfo(wxFacePayResp.getRawdata());
//4、进行人脸识别getWxpayfaceCode获取支付凭证
WxFacePayAuthinfoResp authinfoResp = this.getWxpayfaceCode(wxFaceOrderVo, wxFacePayResp0);
WxPayMicropayResult micropayResult = new WxPayMicropayResult();
if (StringUtil.isNotBlank(authinfoResp.getFace_code())) {
//5、调用后台人脸支付API发起支付
wxFaceOrderVo.setOutTradeNo(getOutTradeNo());
micropayResult = this.toCreateWxOrder(authinfoResp, wxFaceOrderVo, wxFacePayResp0);
//6、向后端查询订单状态 WxPayOrderQueryResult queryResult = queryOrderByNo(micropayResult);
boolean isSuccess = pollOrderStatus(micropayResult);
if (isSuccess) {
//8、更新支付结果updateWxpayfacePayResult
WxFacePayResp updFacePayResp = this.updateWxpayfacePayResult(wxFacePayResp0);
if(ObjUtil.isNotEmpty(updFacePayResp) && WxConstant.STATE_SUCCESS.equals(updFacePayResp.getReturn_code())){
//向后端发起更新订单,进行相应的操作、
this.updatePayResult(micropayResult);
}
} else { //查询失败或者长时间未有结果
//7、撤销交易reverse
WxPayOrderReverseRequest reverseRequest = new WxPayOrderReverseRequest();
reverseRequest.setTransactionId(micropayResult.getTransactionId());
reverseRequest.setOutTradeNo(micropayResult.getOutTradeNo());
WxPayOrderReverseResult reverseResult = this.toReverseOrder(reverseRequest);
}
}
return Result.ok(authinfoResp);
}
/**
* 1 程序启动时初始化 :程序启动时初始化initWxpayface
*
* @return
* @throws JsonProcessingException
*/
@RequestMapping(value = "/initWxpayface", method = RequestMethod.POST)
public WxFacePayResp initWxpayface() throws JsonProcessingException, UnsupportedEncodingException, WxpayFaceSDKDll.DllRegistrationException {
// 构建请求参数的JSON字符串
WxFacePayReq wxFacePayReq = new WxFacePayReq("initWxpayface", "1", System.currentTimeMillis() / 1000, 1);
WxFacePayResp wxFacePayResp = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
System.out.println("**************1、程序启动时初始化" + wxFacePayResp.toString());
return wxFacePayResp;
}
/**
* 2 获取数据getWxpayfaceRawdata
*
* @return
* @throws JsonProcessingException
*/
public 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());
return wxFacePayResp;
}
/**
* 3、获取调用凭证get_wxpayface_authinfo(rawdata)(获取调用凭证)
*
* @return
* @throws Exception
*/
public WxFacePayAuthinfoResp getWxpayfaceAuthinfo(String rawdata) throws Exception {
// 构建请求参数的JSON字符串
WxFacePayAuthinfoResp wxFacePayResp = weChatPayFaceService.getWxFaceAuthInfoReqMap(rawdata);
System.out.println("**************3、获取调用凭证get_wxpayface_authinfo" + wxFacePayResp.toString());
return wxFacePayResp;
}
/**
* 4、进行人脸识别getWxpayfaceCode获取支付凭证
*
* @param wxFaceOrderVo
* @return
* @throws Exception
*/
@RequestMapping(value = "/getWxpayfaceCode", method = RequestMethod.POST)
public WxFacePayAuthinfoResp getWxpayfaceCode(@RequestBody WxFaceOrderVo wxFaceOrderVo, WxFacePayAuthinfoResp wxFacePayResp0) throws Exception {
//4、进行人脸识别getWxpayfaceCode获取支付凭证
String outTradeNo = getOutTradeNo();//获取流水号
// 构建请求参数的JSON字符串
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceCode", "1", System.currentTimeMillis() / 1000);
wxFacePayReq.setAuthinfo(wxFacePayResp0.getAuthinfo())
.setOut_trade_no(outTradeNo)//订单流水号
.setTotal_fee(wxFaceOrderVo.getTotalAmount())//金额:分
/**
* 目标face_code类型可选值"1"刷卡付款码18位数字通过「付款码支付/被扫支付」接口完成支付,
* 如果不填写则默认为"0",人脸付款码:数字字母混合,通过「刷脸支付」接口完成支付。
*/
.setFace_code_type("1");
WxFacePayAuthinfoResp authinfoResp = weChatPayFaceService.getWxpayfaceCode(wxFacePayReq);
System.out.println("**************4、进行人脸识别结果" + authinfoResp.toString());
return authinfoResp;
}
/**
* 从后端获取流水号,保证唯一性
*
* @return
*/
private String getOutTradeNo() {
String url0 = serverUrl + "openapi/wxFacePayOrderApi/getOutTradeNo";
log.info("[WxFacePayController][getWxpayfaceCode][112][获取流水号地址] {}", url0);
String req0 = HttpRequest.post(url0)
.header(Header.CONTENT_TYPE, ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8))
.execute()
.body();
JSONObject tradeNoResult = JSONObject.parseObject(req0);
String outTradeNo = tradeNoResult.getString("result");
System.out.println("获取流水号" + outTradeNo);
return outTradeNo;
}
/**
* 5、向后端进行发起订单支付
*
* @return
*/
private WxPayMicropayResult toCreateWxOrder(WxFacePayAuthinfoResp authinfoResp, WxFaceOrderVo wxFaceOrderVo, WxFacePayAuthinfoResp wxFacePayResp0) {
authinfoResp
.setOut_trade_no(wxFaceOrderVo.getOutTradeNo())//订单流水号
.setTotal_fee(wxFaceOrderVo.getTotalAmount())//金额:分
.setPatientId(wxFaceOrderVo.getPatientId())//患者Id
.setEventModule(wxFaceOrderVo.getEventModule()) //付费模块
.setTerminalId(wxFaceOrderVo.getTerminalId()) //商户机具终端编号
.setAuthinfo(wxFacePayResp0.getAuthinfo())
.setNonce_str(wxFacePayResp0.getNonce_str())
.setSign(wxFacePayResp0.getSign());
JSONObject serverParams = (JSONObject) JSON.toJSON(authinfoResp);
String url = serverUrl + "openapi/wxFacePayOrderApi/createFaceOrder";
log.info("[WxFacePayController][getWxpayfaceCode][153][向后台发起微信刷脸订单创建路径] {}", url);
log.info("[WxFacePayController][getWxpayfaceCode][153][调用后台人脸支付API发起支付参数] {}", serverParams.toString());
String req = HttpRequest.post(url)
.header(Header.CONTENT_TYPE, ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8))
.body(serverParams.toString())
.execute()
.body();
System.out.println("5、向后台发起进行发起订单支付 结果:" + req);
JSONObject serverResult = JSONObject.parseObject(req);
Map<String,Object> result = (Map<String, Object>) serverResult.get("result");
log.info("[WxFacePayController][toCreateWxOrder][140][5、向后端进行发起订单支付请求结果] {}", result.toString());
WxPayMicropayResult micropayResult = new WxPayMicropayResult();
System.out.println("5、调用后台人脸支付API发起支付结果"+result.toString());
if(ObjUtil.isNotEmpty(result)){
micropayResult.setOutTradeNo(result.get("outTradeNo").toString());
micropayResult.setTransactionId(result.get("transactionId").toString());
micropayResult.setTotalFee(Integer.valueOf(result.get("totalFee").toString()));
micropayResult.setReturnCode(result.get("returnCode").toString());
}
return micropayResult;
}
/**
* 轮询逻辑封装方法
* 查询微信刷脸订单状态
* 调用步骤6
*
* @param micropayResult
* @return
*/
public boolean pollOrderStatus(WxPayMicropayResult micropayResult) {
final long timeoutMillis = 60_000; // 60秒超时毫秒
final long pollInterval = 2_000; // 轮询间隔2秒
long startTime = System.currentTimeMillis();
while (true) {
// 1. 查询订单状态
WxPayOrderQueryResult queryResult = this.queryOrderByNo(micropayResult);
// 2. 检查成功状态
if (WxConstant.STATE_SUCCESS.equals(queryResult.getReturnCode())) {
System.out.println("订单支付成功!");
return true;
}
// 3. 检查超时
long elapsed = System.currentTimeMillis() - startTime;
if (elapsed >= timeoutMillis) {
System.out.println("支付超时,未获取成功状态");
return false;
}
// 4. 等待下一次轮询
try {
long nextPoll = Math.min(pollInterval, timeoutMillis - elapsed);
TimeUnit.MILLISECONDS.sleep(nextPoll);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("轮询被中断");
return false;
}
}
}
/**
* 6、向后端查询订单状态
*
* @param micropayResult
* @return
*/
public WxPayOrderQueryResult queryOrderByNo(WxPayMicropayResult micropayResult) {
WxPayOrderQueryResult queryResult = new WxPayOrderQueryResult();
if (ObjUtil.isNotEmpty(micropayResult)) {
JSONObject serverParams = (JSONObject) JSON.toJSON(micropayResult);
String url = serverUrl + "openapi/wxFacePayOrderApi/queryOrderByNo";
log.info("[WxFacePayController][getWxpayfaceCode][184][6、向后台发起查询订单状态创建路径] {}", url);
log.info("[WxFacePayController][getWxpayfaceCode][186][6、向后端查询订单状态参数] {}", serverParams.toString());
String req = HttpRequest.post(url)
.header(Header.CONTENT_TYPE, ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8))
.body(serverParams.toString())
.execute()
.body();
System.out.println("6、后台发起查询订单 结果:" + req);
JSONObject serverResult = JSONObject.parseObject(req);
Map<String,Object> result = (Map<String, Object>) serverResult.get("result");
log.info("[WxFacePayController][toCreateWxOrder][140][6、后台发起查询订单 请求结果] {}", result.toString());
System.out.println("5、调用后台人脸支付API发起支付结果"+result.toString());
if(ObjUtil.isNotEmpty(result)){
queryResult.setReturnCode(result.get("returnCode").toString());
queryResult.setOutTradeNo(result.get("outTradeNo").toString());
queryResult.setTransactionId(result.get("transactionId").toString());
queryResult.setTotalFee(Integer.valueOf(result.get("totalFee").toString()));
}
log.info("[WxFacePayController][toCreateWxOrder][140][ 6、向后端查询订单状态结果] {}", micropayResult.toString());
}
return queryResult;
}
/**
* 7、撤销交易reverse
* 支付交易返回失败或支付系统超时,调用该接口撤销交易。
* 如果此订单用户支付失败,微信支付系统会将此订单关闭;
* 如果用户支付成功,微信支付系统会将此订单资金退还给用户。
* @param reverseRequest
* @return
*/
@RequestMapping(value = "/toReverseOrder", method = RequestMethod.POST)
public WxPayOrderReverseResult toReverseOrder(@RequestBody WxPayOrderReverseRequest reverseRequest) {
WxPayOrderReverseResult reverseResult = new WxPayOrderReverseResult();
if (ObjUtil.isNotEmpty(reverseRequest)) {
JSONObject serverParams = (JSONObject) JSON.toJSON(reverseRequest);
String url = serverUrl + "openapi/wxFacePayOrderApi/reverseOrder";
log.info("[WxFacePayController][toReverseOrder][303][向后台发起撤销交易reverse路径] {}", url);
log.info("[WxFacePayController][toReverseOrder][304][调用后台发起撤销交易参数] {}", serverParams.toString());
String req = HttpRequest.post(url)
.header(Header.CONTENT_TYPE, ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8))
.body(serverParams.toString())
.execute()
.body();
System.out.println("向后台发起撤销交易 结果:" + req);
JSONObject serverResult = JSONObject.parseObject(req);
reverseResult = (WxPayOrderReverseResult) serverResult.get("result");
log.info("[WxFacePayController][toReverseOrder][314][7、向后台发起撤销交易请求结果] {}", reverseResult.toString());
}
return reverseResult;
}
/**
* 8、更新支付结果updateWxpayfacePayResult
*
* @return
* @throws JsonProcessingException
*/
@RequestMapping(value = "/updateWxpayfacePayResult", method = RequestMethod.POST)
public WxFacePayResp updateWxpayfacePayResult(WxFacePayAuthinfoResp wxFacePayResp0) throws JsonProcessingException, UnsupportedEncodingException, WxpayFaceSDKDll.DllRegistrationException {
// 构建请求参数的JSON字符串
WxFacePayReq wxFacePayReq = new WxFacePayReq("updateWxpayfacePayResult", "1", System.currentTimeMillis() / 1000);
wxFacePayReq.setAppid(wxMpProperties.getMchConfig().getAppId())
.setMch_id(wxMpProperties.getMchConfig().getMchId())
.setStore_id(WxConstant.STORE_ID)
.setPayresult("SUCCESS")
.setAuthinfo(wxFacePayResp0.getAuthinfo());
WxFacePayResp wxFacePayResp = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
System.out.println("**************8、更新支付结果updateWxpayfacePayResult" + wxFacePayResp.toString());
return wxFacePayResp;
}
/**
* 11、向后端发起更新状态为成功进行相应的操作
*
* @param micropayResult
* @return
*/
public WxPayOrderQueryResult updatePayResult(WxPayMicropayResult micropayResult) {
WxPayOrderQueryResult queryResult = new WxPayOrderQueryResult();
if (ObjUtil.isNotEmpty(micropayResult)) {
JSONObject serverParams = (JSONObject) JSON.toJSON(micropayResult);
String url = serverUrl + "openapi/wxFacePayOrderApi/updatePayResult";
log.info("[WxFacePayController][updatePayResult][184][11、向后端发起更新状态为成功创建路径] {}", url);
log.info("[WxFacePayController][updatePayResult][186][11、向后端发起更新状态为成功参数] {}", serverParams.toString());
String req = HttpRequest.post(url)
.header(Header.CONTENT_TYPE, ContentType.JSON.toString(CharsetUtil.CHARSET_UTF_8))
.body(serverParams.toString())
.execute()
.body();
System.out.println("11、向后端发起更新状态为成功 结果:" + req);
JSONObject jsonObject = JSONObject.parseObject(req);
Map<String,Object> result = (Map<String, Object>) jsonObject.get("result");
log.info("[WxFacePayController][updatePayResult][140][11、向后端发起更新状态为成功 请求结果] {}", result.toString());
}
return queryResult;
}
/**
* 4、进行人脸识别getWxpayfaceCode获取支付凭证
*
* @return
* @throws Exception
*/
/*@RequestMapping(value = "/getWxpayfaceCode", method = RequestMethod.POST)
public Result<WxFacePayAuthinfoResp> getWxpayfaceCode(@RequestBody WxFaceOrderVo wxFaceOrderVo) throws Exception {
//1 初始化
this.initWxpayface();
//2 获取数据getWxpayfaceRawdata
WxFacePayResp wxFacePayResp = this.getWxpayfaceRawdata();
//String rawdata = wxFacePayResp.getRawdata();
//3、获取调用凭证get_wxpayface_authinfo(rawdata)(获取调用凭证)
WxFacePayAuthinfoResp wxFacePayResp0 = this.getWxpayfaceAuthinfo(wxFacePayResp.getRawdata());
//4、进行人脸识别getWxpayfaceCode获取支付凭证
String outTradeNo = getOutTradeNo();//获取流水号
// 构建请求参数的JSON字符串
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceCode", "1", System.currentTimeMillis() / 1000);
wxFacePayReq.setAuthinfo(wxFacePayResp0.getAuthinfo())
.setOut_trade_no(outTradeNo)//订单流水号
.setTotal_fee(wxFaceOrderVo.getTotalAmount())//金额:分
*/
/**
* 目标face_code类型可选值"1"刷卡付款码18位数字通过「付款码支付/被扫支付」接口完成支付,
* 如果不填写则默认为"0",人脸付款码:数字字母混合,通过「刷脸支付」接口完成支付。
*/
/*
.setFace_code_type("1");
WxFacePayAuthinfoResp authinfoResp = weChatPayFaceService.getWxpayfaceCode(wxFacePayReq);
System.out.println("**************4、进行人脸识别结果" + authinfoResp.toString());
if (StringUtil.isNotBlank(authinfoResp.getFace_code())) {
//5、调用后台人脸支付API发起支付
WxPayMicropayResult micropayResult = this.toCreateWxOrder(authinfoResp, wxFaceOrderVo, wxFacePayResp0);
//6、向后端查询订单状态
//WxPayOrderQueryResult queryResult = queryOrderByNo(micropayResult);
boolean isSuccess = pollOrderStatus(micropayResult);
if (isSuccess) {
}
}
return Result.ok(authinfoResp);
}
*/
}

View File

@@ -10,13 +10,16 @@ import com.dpkj.modules.scanface.wx.vo.WxFacePayAuthinfoResp;
import com.dpkj.modules.scanface.wx.vo.WxFacePayReq; import com.dpkj.modules.scanface.wx.vo.WxFacePayReq;
import com.dpkj.modules.scanface.wx.vo.WxFacePayResp; import com.dpkj.modules.scanface.wx.vo.WxFacePayResp;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.util.StringUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.Provider; import java.security.Provider;
import java.security.Security; import java.security.Security;
import java.util.HashMap; import java.util.HashMap;
@@ -30,7 +33,7 @@ import java.util.TreeSet;
*/ */
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/wxpayFace") @RequestMapping("/wxpayFaceTest")
public class WxpayFaceTestController { public class WxpayFaceTestController {
@Resource @Resource
@@ -41,6 +44,7 @@ public class WxpayFaceTestController {
/** /**
* 1 程序启动时初始化 :程序启动时初始化initWxpayface * 1 程序启动时初始化 :程序启动时初始化initWxpayface
*
* @return * @return
* @throws JsonProcessingException * @throws JsonProcessingException
*/ */
@@ -54,9 +58,9 @@ public class WxpayFaceTestController {
} }
/** /**
* 2 获取数据getWxpayfaceRawdata * 2 获取数据getWxpayfaceRawdata
*
* @return * @return
* @throws JsonProcessingException * @throws JsonProcessingException
*/ */
@@ -74,21 +78,22 @@ public class WxpayFaceTestController {
/** /**
* 3、获取调用凭证get_wxpayface_authinfo(rawdata)(获取调用凭证) * 3、获取调用凭证get_wxpayface_authinfo(rawdata)(获取调用凭证)
*
* @return * @return
* @throws Exception * @throws Exception
*/ */
@RequestMapping(value = "/getWxpayfaceAuthinfo", method = RequestMethod.POST) @RequestMapping(value = "/getWxpayfaceAuthinfo", method = RequestMethod.POST)
public Result<Map<String, Object>> getWxpayfaceAuthinfo() throws Exception { public Result<WxFacePayAuthinfoResp> getWxpayfaceAuthinfo() throws Exception {
Map<String, Object> wxFacePayResp = new HashMap<>();
// 构建请求参数的JSON字符串 // 构建请求参数的JSON字符串
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceRawdata", "1", System.currentTimeMillis() / 1000); WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceRawdata", "1", System.currentTimeMillis() / 1000);
WxFacePayResp wxFacePayResp1 = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq); WxFacePayResp wxFacePayResp1 = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
System.out.println("**************2、获取数据getWxpayfaceRawdata"+wxFacePayResp1.toString()); System.out.println("**************3、获取数据getWxpayfaceRawdata" + wxFacePayResp1.toString());
WxFacePayAuthinfoResp wxFacePayResp = new WxFacePayAuthinfoResp();
if ("SUCCESS".equals(wxFacePayResp1.getReturn_code())) { if ("SUCCESS".equals(wxFacePayResp1.getReturn_code())) {
String rawdata = wxFacePayResp1.getRawdata(); String rawdata = wxFacePayResp1.getRawdata();
// 构建请求参数的JSON字符串 // 构建请求参数的JSON字符串
wxFacePayResp = weChatPayFaceService.getWxFaceAuthInfoReqMap(rawdata); wxFacePayResp = weChatPayFaceService.getWxFaceAuthInfoReqMap(rawdata);
System.out.println("**************2、获取调用凭证get_wxpayface_authinfo"+wxFacePayResp.toString()); System.out.println("**************3、获取调用凭证get_wxpayface_authinfo" + wxFacePayResp.toString());
} }
return Result.ok(wxFacePayResp); return Result.ok(wxFacePayResp);
} }
@@ -96,35 +101,49 @@ public class WxpayFaceTestController {
/** /**
* 4、进行人脸识别getWxpayfaceCode获取支付凭证 * 4、进行人脸识别getWxpayfaceCode获取支付凭证
*
* @return * @return
* @throws Exception * @throws Exception
*/ */
@RequestMapping(value = "/getWxpayfaceCode", method = RequestMethod.POST) @RequestMapping(value = "/getWxpayfaceCode", method = RequestMethod.POST)
public Result<WxFacePayAuthinfoResp> getWxpayfaceCode() throws Exception { public Result<WxFacePayAuthinfoResp> getWxpayfaceCode() throws Exception {
WxFacePayAuthinfoResp wxFacePayResp0 = new WxFacePayAuthinfoResp();
// 构建请求参数的JSON字符串
WxFacePayReq wxFacePayReq0 = new WxFacePayReq("getWxpayfaceRawdata", "1", System.currentTimeMillis() / 1000);
WxFacePayResp wxFacePayResp1 = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq0);
System.out.println("**************3、获取数据getWxpayfaceRawdata" + wxFacePayResp1.toString());
if ("SUCCESS".equals(wxFacePayResp1.getReturn_code())) {
String rawdata = wxFacePayResp1.getRawdata();
// 构建请求参数的JSON字符串
wxFacePayResp0 = weChatPayFaceService.getWxFaceAuthInfoReqMap(rawdata);
System.out.println("**************3、获取调用凭证get_wxpayface_authinfo" + wxFacePayResp0.toString());
// 构建请求参数的JSON字符串 // 构建请求参数的JSON字符串
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceCode", "1", System.currentTimeMillis() / 1000); WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceCode", "1", System.currentTimeMillis() / 1000);
wxFacePayReq.setAuthinfo(wxFacePayResp0.getAuthinfo())
.setOut_trade_no("")//订单流水号
.setTotal_fee(new String("1"));
WxFacePayAuthinfoResp authinfoResp = weChatPayFaceService.doWxPayMethod(wxFacePayReq); WxFacePayAuthinfoResp authinfoResp = weChatPayFaceService.getWxpayfaceCode(wxFacePayReq);
System.out.println("**************4、进行人脸识别"+authinfoResp.toString()); System.out.println("**************4、进行人脸识别结果" + authinfoResp.toString());
if (StringUtil.isNotBlank(authinfoResp.getFace_code())) {
//调用后台人脸支付API发起支付
authinfoResp.setOut_trade_no(wxFacePayReq.getOut_trade_no())//订单流水号
.setTotal_fee(wxFacePayReq.getTotal_fee());
}
return Result.ok(authinfoResp); return Result.ok(authinfoResp);
} else {
return Result.error("微信获取调用凭证失败");
} }
}
//5、进行发起订单支付 //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 列表,以及所有签名算法 //可以打印 JDK 中的 Provider 列表,以及所有签名算法
public void outProvider() { public void outProvider() {
TreeSet<String> algorithms = new TreeSet<>(); TreeSet<String> algorithms = new TreeSet<>();

View File

@@ -16,14 +16,14 @@ public class WxpayFaceSDKDll {
* 获取 Dll 实例,同时注册 Dll 控件。 * 获取 Dll 实例,同时注册 Dll 控件。
* *
* @return WxpayFaceSDKDll 实例 * @return WxpayFaceSDKDll 实例
* @throws WxpayFaceSDKDll.DllRegistrationException 如果注册控件失败,抛出此异常 * @throws DllRegistrationException 如果注册控件失败,抛出此异常
*/ */
public static WxpayFaceSDKDll.Dll instance() throws DllRegistrationException { public static Dll instance() throws DllRegistrationException {
try { try {
return Native.load("WxpayFaceSDK", WxpayFaceSDKDll.Dll.class); return Native.load("WxpayFaceSDK", Dll.class);
} catch (UnsatisfiedLinkError e) { } catch (UnsatisfiedLinkError e) {
log.info("[WxpayFaceSDK][instance][微信扫脸动态库] SDK注册失败{}", e.getMessage()); log.info("[WxpayFaceSDK][instance][微信扫脸动态库] SDK注册失败{}", e.getMessage());
throw new WxpayFaceSDKDll.DllRegistrationException("Failed to load WxpayFaceSDK library: ", e); throw new DllRegistrationException("Failed to load WxpayFaceSDK library: ", e);
} }
} }

View File

@@ -19,6 +19,7 @@ public interface WeChatPayFaceService {
/** /**
* 调用方法 * 调用方法
* 1、程序启动时初始化initWxpayface2、获取数据getWxpayfaceRawdata * 1、程序启动时初始化initWxpayface2、获取数据getWxpayfaceRawdata
* 8、更新支付结果updateWxpayfacePayResult
* @param wxFacePayReq * @param wxFacePayReq
* @return * @return
* @throws UnsupportedEncodingException * @throws UnsupportedEncodingException
@@ -36,7 +37,7 @@ public interface WeChatPayFaceService {
* @Param rawData 初始化数据。由微信人脸SDK的接口返回。 * @Param rawData 初始化数据。由微信人脸SDK的接口返回。
* @return: java.util.Map<java.lang.String,java.lang.String> * @return: java.util.Map<java.lang.String,java.lang.String>
*/ */
Map<String, Object> getWxFaceAuthInfoReqMap(String rawData) throws Exception; WxFacePayAuthinfoResp getWxFaceAuthInfoReqMap(String rawData) throws Exception;
/** /**
@@ -47,7 +48,6 @@ public interface WeChatPayFaceService {
* @throws UnsupportedEncodingException * @throws UnsupportedEncodingException
* @throws JsonProcessingException * @throws JsonProcessingException
*/ */
WxFacePayAuthinfoResp doWxPayMethod(WxFacePayReq wxFacePayReq) throws UnsupportedEncodingException, JsonProcessingException, WxpayFaceSDKDll.DllRegistrationException; WxFacePayAuthinfoResp getWxpayfaceCode(WxFacePayReq wxFacePayReq) throws UnsupportedEncodingException, JsonProcessingException, WxpayFaceSDKDll.DllRegistrationException;
} }

View File

@@ -7,6 +7,7 @@ import com.sun.jna.Memory;
import com.sun.jna.Pointer; import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@@ -27,10 +28,8 @@ public class CallWxpayFaceServiceImpl implements CallWxpayFaceService {
} }
//赋值 //赋值
private static WxMpProperties wxMpProperties; @Autowired
public static void setWxMpConfiguration(WxMpProperties wxMpProperties) { private WxMpProperties wxMpProperties;
CallWxpayFaceServiceImpl.wxMpProperties = wxMpProperties;
}
/** /**
@@ -46,7 +45,7 @@ public class CallWxpayFaceServiceImpl implements CallWxpayFaceService {
reqPointer.setString(0, reqJson); reqPointer.setString(0, reqJson);
//请求数据长度 //请求数据长度
int reqSize = reqPointer.getString(0).length(); int reqSize = reqPointer.getString(0).length();
System.out.println("-----------调用微信刷脸请求数据----------"+reqPointer.getString(0)); System.out.println("-----------调用微信刷脸DLL请求数据----------"+reqPointer.getString(0));
//接收响应 //接收响应
long[] pRespBuf = new long[1]; long[] pRespBuf = new long[1];
@@ -64,7 +63,7 @@ public class CallWxpayFaceServiceImpl implements CallWxpayFaceService {
byte[] byteArray = pointer.getByteArray(0, respSize[0]); byte[] byteArray = pointer.getByteArray(0, respSize[0]);
resStr = new String(byteArray, StandardCharsets.UTF_8); resStr = new String(byteArray, StandardCharsets.UTF_8);
System.out.println("-----------调用服务成功结果: " + resStr); System.out.println("-----------调用微信刷脸DLL请求结果: " + resStr);
dll.wxpayReleaseResponse(new String[2]); dll.wxpayReleaseResponse(new String[2]);
//释放 C:\Windows\System32目录下 WxpayFaceSDK.INSTANCE.wxpayReleaseResponse(new String[2]); //释放 C:\Windows\System32目录下 WxpayFaceSDK.INSTANCE.wxpayReleaseResponse(new String[2]);
} else { } else {

View File

@@ -1,5 +1,6 @@
package com.dpkj.modules.scanface.wx.service.impl; package com.dpkj.modules.scanface.wx.service.impl;
import com.dpkj.common.constant.WxConstant;
import com.dpkj.modules.scanface.wx.config.WechatUrlConfig; import com.dpkj.modules.scanface.wx.config.WechatUrlConfig;
import com.dpkj.modules.scanface.wx.config.WxMpProperties; import com.dpkj.modules.scanface.wx.config.WxMpProperties;
import com.dpkj.modules.scanface.wx.dll.WxpayFaceSDKDll; import com.dpkj.modules.scanface.wx.dll.WxpayFaceSDKDll;
@@ -7,6 +8,7 @@ import com.dpkj.modules.scanface.wx.service.CallWxpayFaceService;
import com.dpkj.modules.scanface.wx.service.WeChatPayFaceService; import com.dpkj.modules.scanface.wx.service.WeChatPayFaceService;
import com.dpkj.modules.scanface.wx.util.WXPayUtil; import com.dpkj.modules.scanface.wx.util.WXPayUtil;
import com.dpkj.modules.scanface.wx.util.WxRandomUtils; import com.dpkj.modules.scanface.wx.util.WxRandomUtils;
import com.dpkj.modules.scanface.wx.util.XmlParserUtil;
import com.dpkj.modules.scanface.wx.util.XmlUtils; import com.dpkj.modules.scanface.wx.util.XmlUtils;
import com.dpkj.modules.scanface.wx.vo.WxFacePayAuthinfoResp; import com.dpkj.modules.scanface.wx.vo.WxFacePayAuthinfoResp;
import com.dpkj.modules.scanface.wx.vo.WxFacePayMicroPayResp; import com.dpkj.modules.scanface.wx.vo.WxFacePayMicroPayResp;
@@ -79,7 +81,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
reqPointer.setString(0, reqJson); reqPointer.setString(0, reqJson);
//请求数据长度 //请求数据长度
int reqSize = reqPointer.getString(0).length(); int reqSize = reqPointer.getString(0).length();
System.out.println("-----------调用微信刷脸请求数据----------" + reqPointer.getString(0)); System.out.println("-----------调用微信刷脸DLL请求数据----------" + reqPointer.getString(0));
//接收响应 //接收响应
long[] pRespBuf = new long[1]; long[] pRespBuf = new long[1];
@@ -98,7 +100,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
byte[] byteArray = pointer.getByteArray(0, respSize[0]); byte[] byteArray = pointer.getByteArray(0, respSize[0]);
resStr = new String(byteArray, StandardCharsets.UTF_8); resStr = new String(byteArray, StandardCharsets.UTF_8);
System.out.println("-----------调用服务成功结果: " + resStr); System.out.println("-----------微信刷脸DLL调用服务成功结果: " + resStr);
//释放 //释放
dll.wxpayReleaseResponse(new String[2]); dll.wxpayReleaseResponse(new String[2]);
@@ -124,16 +126,17 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
* @return: java.util.Map<java.lang.String, java.lang.String> * @return: java.util.Map<java.lang.String, java.lang.String>
*/ */
@Override @Override
public Map<String, Object> getWxFaceAuthInfoReqMap(String rawData) throws Exception { public WxFacePayAuthinfoResp getWxFaceAuthInfoReqMap(String rawData) throws Exception {
try {
SortedMap<String, String> map = new TreeMap<String, String>(); SortedMap<String, String> map = new TreeMap<String, String>();
//门店编号, 由商户定义, 各门店唯一。 //门店编号, 由商户定义, 各门店唯一。
map.put("store_id", "1111111111111"); map.put("store_id", WxConstant.STORE_ID);
//门店名称,由商户定义。(可用于展示);中文会导致调用失败 //门店名称,由商户定义。(可用于展示);中文会导致调用失败
String text = "刷脸设备一号"; String text = WxConstant.STORE_TEXT;
String storeName = Base64.getEncoder().encodeToString(text.getBytes()); String storeName = Base64.getEncoder().encodeToString(text.getBytes());
map.put("store_name", storeName); map.put("store_name", storeName);
//终端设备编号,由商户定义 //终端设备编号,由商户定义
map.put("device_id", "test111"); map.put("device_id", WxConstant.DEVICE_ID);
//初始化数据。由微信人脸SDK的接口返回。 //初始化数据。由微信人脸SDK的接口返回。
map.put("rawdata", rawData); map.put("rawdata", rawData);
//商户号绑定的公众号/小程序 appid //商户号绑定的公众号/小程序 appid
@@ -145,16 +148,16 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
String timestamp = String.format("%010d", timeStampSec); String timestamp = String.format("%010d", timeStampSec);
map.put("now", timestamp); map.put("now", timestamp);
//版本号。固定为1 //版本号。固定为1
map.put("version", "1"); map.put("version", WxConstant.VERSION);
//随机字符串不长于32位:工具类微信随机数 //随机字符串不长于32位:工具类微信随机数
map.put("nonce_str", WxRandomUtils.getNonceStr()); map.put("nonce_str", WxRandomUtils.getNonceStr());
//参数签名,使用MD5 //参数签名,使用MD5
map.put("sign_type", "MD5"); map.put("sign_type", WxConstant.SING_TYPE);
//加密和生成微信v2指定的xml格式 //加密和生成微信v2指定的xml格式
// WXPayUtil.createSign("UTF-8",map,wxMpProperties.getMchConfig().getKeyApi()); // WXPayUtil.createSign("UTF-8",map,wxMpProperties.getMchConfig().getKeyApi());
String sign = WXPayUtil.generateSignedXml(map, wxMpProperties.getMchConfig().getKeyApi(), WxPayConstants.SignType.MD5); String sign = WXPayUtil.generateSignedXml(map, wxMpProperties.getMchConfig().getKeyApi(), WxPayConstants.SignType.MD5);
log.info("--------构建微信获取刷脸授权XML参数{}", sign); log.info("--------3、获取调用凭证 构建微信获取刷脸授权XML参数{}", sign);
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
HttpEntity<String> stringHttpEntity = new HttpEntity<String>(sign, headers); HttpEntity<String> stringHttpEntity = new HttpEntity<String>(sign, headers);
@@ -164,16 +167,25 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
HttpMethod.POST, HttpMethod.POST,
stringHttpEntity, stringHttpEntity,
String.class); String.class);
log.info("--------发起http调用结果{}", exchange.getBody()); log.info("--------3、获取调用凭证 发起http调用结果{}", exchange.getBody());
XmlParserUtil.extractAuthInfo(exchange.getBody());
//转成map方便取值 //转成map方便取值
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); Map<String, String> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
log.info("------3、获取调用凭证 调用结果转换为map{}", stringMap);
//转成返回对象 //转成返回对象
ObjectMapper mapper = new ObjectMapper(); WxFacePayAuthinfoResp wxFacePayAuthinfoResp = XmlUtils.mapToObject(
WxFacePayAuthinfoResp wxFacePayAuthinfoResp = mapper.readValue(exchange.getBody(), WxFacePayAuthinfoResp.class); stringMap,
log.info("--------发起http调用结果转换", wxFacePayAuthinfoResp.toString()); WxFacePayAuthinfoResp.class
);
log.info("--------发起http调用结果转换为WxFacePayAuthinfoResp", wxFacePayAuthinfoResp.toString());
return stringMap; return wxFacePayAuthinfoResp;
} catch (Exception e) {
e.printStackTrace();
return null;
}
} }
@@ -187,7 +199,14 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
* @throws JsonProcessingException * @throws JsonProcessingException
*/ */
@Override @Override
public WxFacePayAuthinfoResp doWxPayMethod(WxFacePayReq wxFacePayReq) throws JsonProcessingException, UnsupportedEncodingException, WxpayFaceSDKDll.DllRegistrationException { public WxFacePayAuthinfoResp getWxpayfaceCode(WxFacePayReq wxFacePayReq) throws JsonProcessingException, UnsupportedEncodingException, WxpayFaceSDKDll.DllRegistrationException {
//设置参数
wxFacePayReq.setAppid(wxMpProperties.getMchConfig().getAppId())
.setMch_id(wxMpProperties.getMchConfig().getMchId())
.setStore_id(WxConstant.STORE_ID)
.setFace_authtype(WxConstant.FACEPAY)
.setAuthinfo(wxFacePayReq.getAuthinfo());
// 构建请求参数的JSON字符串 // 构建请求参数的JSON字符串
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
String req = mapper.writeValueAsString(wxFacePayReq); String req = mapper.writeValueAsString(wxFacePayReq);
@@ -195,6 +214,8 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
// 创建一个Pointer来接收响应 // 创建一个Pointer来接收响应
List<String> pResp = new ArrayList<>(); List<String> pResp = new ArrayList<>();
String result = callWxpayFaceService.callWxpayFaceService(req, pResp); String result = callWxpayFaceService.callWxpayFaceService(req, pResp);
System.out.println("4、进行人脸识别getWxpayfaceCode结果"+result);
log.info("[WeChatPayFaceServiceImpl][getWxpayfaceCode][220][4、进行人脸识别getWxpayfaceCode结果] {}", result);
//响应结果 //响应结果
WxFacePayAuthinfoResp authinfoResp = mapper.readValue(result, WxFacePayAuthinfoResp.class); WxFacePayAuthinfoResp authinfoResp = mapper.readValue(result, WxFacePayAuthinfoResp.class);
@@ -203,7 +224,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
//5、进行发起订单支付 //5、进行发起订单支付
public Map<String, Object> createWxOrder() throws Exception { public Map<String, String> createWxOrder() throws Exception {
SortedMap<String, String> map = new TreeMap<String, String>(); SortedMap<String, String> map = new TreeMap<String, String>();
//微信分配的公众账号ID企业号corpid即为此appId //微信分配的公众账号ID企业号corpid即为此appId
map.put("appid", wxMpProperties.getMchConfig().getAppId()); map.put("appid", wxMpProperties.getMchConfig().getAppId());
@@ -238,7 +259,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
String.class); String.class);
log.info("--------5、进行发起订单支付:发起http调用结果【{}】", exchange.getBody()); log.info("--------5、进行发起订单支付:发起http调用结果【{}】", exchange.getBody());
//转成map方便取值 //转成map方便取值
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); Map<String, String> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
//转成返回对象 //转成返回对象
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
@@ -250,7 +271,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
//6、查询订单状态 //6、查询订单状态
public Map<String, Object> orderquery() throws Exception { public Map<String, String> orderquery() throws Exception {
SortedMap<String, String> map = new TreeMap<String, String>(); SortedMap<String, String> map = new TreeMap<String, String>();
//微信支付分配的公众账号ID企业号corpid即为此appId //微信支付分配的公众账号ID企业号corpid即为此appId
map.put("appid", wxMpProperties.getMchConfig().getAppId()); map.put("appid", wxMpProperties.getMchConfig().getAppId());
@@ -278,7 +299,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
String.class); String.class);
log.info("--------6、查询订单状态,发起http调用结果【{}】", exchange.getBody()); log.info("--------6、查询订单状态,发起http调用结果【{}】", exchange.getBody());
//转成map方便取值 //转成map方便取值
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); Map<String, String> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
//转成返回对象 //转成返回对象
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
@@ -290,7 +311,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
//7、撤销交易 //7、撤销交易
public Map<String, Object> reverse() throws Exception { public Map<String, String> reverse() throws Exception {
SortedMap<String, String> map = new TreeMap<String, String>(); SortedMap<String, String> map = new TreeMap<String, String>();
//微信分配的公众账号ID企业号corpid即为此appId //微信分配的公众账号ID企业号corpid即为此appId
map.put("appid", wxMpProperties.getMchConfig().getAppId()); map.put("appid", wxMpProperties.getMchConfig().getAppId());
@@ -317,7 +338,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
String.class); String.class);
log.info("--------7、撤销交易,发起http调用结果【{}】", exchange.getBody()); log.info("--------7、撤销交易,发起http调用结果【{}】", exchange.getBody());
//转成map方便取值 //转成map方便取值
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); Map<String, String> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
//转成返回对象 //转成返回对象
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();

View File

@@ -0,0 +1,45 @@
package com.dpkj.modules.scanface.wx.util;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayInputStream;
/**
* @description: 解析微信返回的xml数据
* @author: Zhangxue
* @time: 2025/5/28 10:10
*/
public class XmlParserUtil {
/**
* 解析微信返回的xml数据获取到authinfo
* @param xmlResponse
* @return
* @throws Exception
*/
public static String extractAuthInfo(String xmlResponse) throws Exception {
// 1. 创建DocumentBuilder解析XML
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
// 2. 将字符串转为输入流
ByteArrayInputStream input = new ByteArrayInputStream(xmlResponse.getBytes("UTF-8"));
Document doc = builder.parse(input);
// 3. 创建XPath表达式定位<authinfo>节点
XPath xpath = XPathFactory.newInstance().newXPath();
String expression = "//authinfo"; // 使用XPath查找所有authinfo节点
// 4. 提取节点文本内容自动处理CDATA
Node authInfoNode = (Node) xpath.evaluate(expression, doc, XPathConstants.NODE);
if (authInfoNode != null) {
return authInfoNode.getTextContent();
} else {
throw new RuntimeException("未找到<authinfo>节点");
}
}
}

View File

@@ -8,6 +8,7 @@ import org.dom4j.Element;
import org.dom4j.io.SAXReader; import org.dom4j.io.SAXReader;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@@ -20,6 +21,7 @@ import java.util.Map;
*/ */
public class XmlUtils { public class XmlUtils {
/** /**
* xml解析器 * xml解析器
* *
@@ -32,8 +34,8 @@ public class XmlUtils {
* @返回子节点属性值:->节点名->子节点名=>属性名:属性值 * @返回子节点属性值:->节点名->子节点名=>属性名:属性值
* @返回子节点值:->节点名->子节点名:属性值 * @返回子节点值:->节点名->子节点名:属性值
*/ */
public static Map<String, Object> xmlParser(String xml, String filterRootEleName) { public static Map<String, String> xmlParser(String xml, String filterRootEleName) {
Map<String, Object> retMap = new HashMap<>(); Map<String, String> retMap = new HashMap<>();
//1.创建Reader对象 //1.创建Reader对象
try { try {
SAXReader reader = new SAXReader(); SAXReader reader = new SAXReader();
@@ -56,14 +58,14 @@ public class XmlUtils {
* @param eleKey 上级节点key * @param eleKey 上级节点key
* @param retMap 返回map * @param retMap 返回map
*/ */
private static void parser(Element ele, StringBuilder eleKey, String firstEleName, Map<String, Object> retMap) { private static void parser(Element ele, StringBuilder eleKey, String firstEleName, Map<String, String> retMap) {
StringBuilder builder = new StringBuilder(eleKey.toString()); StringBuilder builder = new StringBuilder();//eleKey.toString()
if (StringUtils.isEmpty(firstEleName) if (StringUtils.isEmpty(firstEleName)
|| firstEleName.equals(ele.getName())) { || firstEleName.equals(ele.getName())) {
firstEleName = null; firstEleName = null;
builder.append("->" + ele.getName()); //builder.append("->" + ele.getName());
if (org.apache.commons.lang3.StringUtils.isNotEmpty(org.apache.commons.lang3.StringUtils.stripToEmpty(ele.getData() + ""))) { if (StringUtils.isNotEmpty(StringUtils.stripToEmpty(ele.getData() + ""))) {
retMap.put(builder.toString(), org.apache.commons.lang3.StringUtils.stripToEmpty(ele.getData() + "")); retMap.put(ele.getName(), StringUtils.stripToEmpty(ele.getData() + ""));
} }
List<Attribute> attributes = ele.attributes(); List<Attribute> attributes = ele.attributes();
for (Attribute attribute : attributes) { for (Attribute attribute : attributes) {
@@ -82,4 +84,31 @@ public class XmlUtils {
} }
/**
* 通用方法将Map转换为Java对象
*/
public static <T> T mapToObject(Map<String, String> map, Class<T> clazz) throws Exception {
T obj = clazz.getDeclaredConstructor().newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
String value = map.get(fieldName);
if (value != null) {
Class<?> type = field.getType();
// 类型转换逻辑
if (type == int.class || type == Integer.class) {
field.set(obj, Integer.parseInt(value));
} else if (type == boolean.class || type == Boolean.class) {
field.set(obj, Boolean.parseBoolean(value));
} else {
field.set(obj, value);
}
}
}
return obj;
}
} }

View File

@@ -0,0 +1,43 @@
package com.dpkj.modules.scanface.wx.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @description: 微信刷脸订单参数
* @author: Zhangxue
* @time: 2025/5/28 15:35
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class WxFaceOrderVo {
/**
* 付款模块
*/
private String eventModule;
/**
* 患者Id
*/
private String patientId;
/**
* 商户机具终端编号
*/
private String terminalId;
/**
* 系统订单编号
*/
private String outTradeNo;
/**
* 用户支付金额 分
*/
private String totalAmount;
}

View File

@@ -121,4 +121,46 @@ public class WxFacePayAuthinfoResp {
* 用户身份信息查询凭证 * 用户身份信息查询凭证
*/ */
private String face_sid; private String face_sid;
/**
* 传参到后台发起微信订单方法
* 4、进行人脸识别
* 必填:否
* 订单金额(数字), 单位分该字段在在face_code_type为"1"时可不填,为"0"时必填
*/
private String total_fee;
/**
* 传参到后台发起微信订单方法
* 4、进行人脸识别
* 必填:否
* 商户订单号须与调用支付接口时字段一致该字段在在face_code_type为"1"时可不填,为"0"时必填
*/
private String out_trade_no;
/**
* 传参到后台发起微信订单方法
* 商品描述
*/
private String remark;
/**
* 传参到后台发起微信订单方法
* 患者Id
*/
private String patientId;
/**
* 传参到后台发起微信订单方法
* 付款模块
*/
private String eventModule;
/**
* 传参到后台发起微信订单方法
* 商户机具终端编号
*/
private String terminalId;
} }

View File

@@ -35,6 +35,12 @@ public class WxFacePayReq {
*/ */
private long now; private long now;
/**
* 对摄像头画面进行旋转1为+90度2为180度3为-90度
*/
private int camera_rotation;
/** /**
* 4、进行人脸识别 * 4、进行人脸识别
* 必填:是 * 必填:是
@@ -54,14 +60,14 @@ public class WxFacePayReq {
* 必填:否 * 必填:否
* 子商户绑定的公众号/小程序 appid(可不填) * 子商户绑定的公众号/小程序 appid(可不填)
*/ */
private String sub_appid; //private String sub_appid;
/** /**
* 4、进行人脸识别 * 4、进行人脸识别
* 必填:否 * 必填:否
* 子商户号(非服务商模式不填) * 子商户号(非服务商模式不填)
*/ */
private String sub_mch_id; //private String sub_mch_id;
/** /**
* 4、进行人脸识别 * 4、进行人脸识别
@@ -75,7 +81,7 @@ public class WxFacePayReq {
* 必填:否 * 必填:否
* 通过getWxpayfaceUserInfo获取的openid传入后可使用快捷支付模式。1.24版本以上支持该参数 * 通过getWxpayfaceUserInfo获取的openid传入后可使用快捷支付模式。1.24版本以上支持该参数
*/ */
private String openid; //private String openid;
/** /**
* 4、进行人脸识别 * 4、进行人脸识别
@@ -119,21 +125,21 @@ public class WxFacePayReq {
* 指定刷脸界面显示的屏幕编号。 * 指定刷脸界面显示的屏幕编号。
* 编号1为主屏幕其余屏幕按系统设置中的顺序从2开始编号常用场景举例双屏机器上传"2"即可显示在副屏上。如果不填写则默认显示在主屏幕。1.18版本以上支持该参数 * 编号1为主屏幕其余屏幕按系统设置中的顺序从2开始编号常用场景举例双屏机器上传"2"即可显示在副屏上。如果不填写则默认显示在主屏幕。1.18版本以上支持该参数
*/ */
private String screen_index; //private String screen_index;
/** /**
* 4、进行人脸识别 * 4、进行人脸识别
* 必填:否 * 必填:否
* 设置不接受外接键盘输入,可选值:"1"禁用。1.23版本以上支持该参数 * 设置不接受外接键盘输入,可选值:"1"禁用。1.23版本以上支持该参数
*/ */
private String disable_keyboard; //private String disable_keyboard;
/** /**
* 4、进行人脸识别 * 4、进行人脸识别
* 必填:否 * 必填:否
* 设置刷脸窗口以无焦点方式启动,可选值:"1"无焦点启动窗口。1.26版本以上支持该参数 * 设置刷脸窗口以无焦点方式启动,可选值:"1"无焦点启动窗口。1.26版本以上支持该参数
*/ */
private String use_window_nofocus; //private String use_window_nofocus;
/** /**
@@ -151,4 +157,13 @@ public class WxFacePayReq {
this.now = now; this.now = now;
} }
//构建
public WxFacePayReq(String cmd, String version, long now,int camera_rotation) {
this.cmd= cmd;
this.version =version;
this.now = now;
this.camera_rotation = camera_rotation;
}
} }