微信刷脸
This commit is contained in:
42
src/main/java/com/dpkj/common/constant/WxConstant.java
Normal file
42
src/main/java/com/dpkj/common/constant/WxConstant.java
Normal 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";
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -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.WxFacePayResp;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import jodd.util.StringUtil;
|
||||
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 org.thymeleaf.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.util.HashMap;
|
||||
@@ -30,7 +33,7 @@ import java.util.TreeSet;
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/wxpayFace")
|
||||
@RequestMapping("/wxpayFaceTest")
|
||||
public class WxpayFaceTestController {
|
||||
|
||||
@Resource
|
||||
@@ -41,31 +44,32 @@ public class WxpayFaceTestController {
|
||||
|
||||
/**
|
||||
* 1 程序启动时初始化 :程序启动时初始化initWxpayface
|
||||
*
|
||||
* @return
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
@RequestMapping(value = "/initWxpayface", method = RequestMethod.GET)
|
||||
public Result<WxFacePayResp> initWxpayface() throws JsonProcessingException, UnsupportedEncodingException, WxpayFaceSDKDll.DllRegistrationException {
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("initWxpayface","1",System.currentTimeMillis()/1000);
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("initWxpayface", "1", System.currentTimeMillis() / 1000);
|
||||
WxFacePayResp wxFacePayResp = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
|
||||
System.out.println("**************1、程序启动时初始化:"+wxFacePayResp.toString());
|
||||
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);
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceRawdata", "1", System.currentTimeMillis() / 1000);
|
||||
WxFacePayResp wxFacePayResp = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
|
||||
System.out.println("**************2、获取数据:"+wxFacePayResp.toString());
|
||||
System.out.println("**************2、获取数据:" + wxFacePayResp.toString());
|
||||
|
||||
String rawdata = wxFacePayResp.getRawdata();
|
||||
return Result.ok(wxFacePayResp);
|
||||
@@ -74,21 +78,22 @@ public class WxpayFaceTestController {
|
||||
|
||||
/**
|
||||
* 3、获取调用凭证get_wxpayface_authinfo(rawdata)(获取调用凭证)
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(value = "/getWxpayfaceAuthinfo", method = RequestMethod.POST)
|
||||
public Result<Map<String, Object>> getWxpayfaceAuthinfo() throws Exception {
|
||||
Map<String, Object> wxFacePayResp = new HashMap<>();
|
||||
public Result<WxFacePayAuthinfoResp> getWxpayfaceAuthinfo() throws Exception {
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceRawdata","1",System.currentTimeMillis()/1000);
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceRawdata", "1", System.currentTimeMillis() / 1000);
|
||||
WxFacePayResp wxFacePayResp1 = weChatPayFaceService.doWxPayIniMethod(wxFacePayReq);
|
||||
System.out.println("**************2、获取数据getWxpayfaceRawdata:"+wxFacePayResp1.toString());
|
||||
if("SUCCESS".equals(wxFacePayResp1.getReturn_code())){
|
||||
System.out.println("**************3、获取数据getWxpayfaceRawdata:" + wxFacePayResp1.toString());
|
||||
WxFacePayAuthinfoResp wxFacePayResp = new WxFacePayAuthinfoResp();
|
||||
if ("SUCCESS".equals(wxFacePayResp1.getReturn_code())) {
|
||||
String rawdata = wxFacePayResp1.getRawdata();
|
||||
// 构建请求参数的JSON字符串
|
||||
wxFacePayResp= weChatPayFaceService.getWxFaceAuthInfoReqMap(rawdata);
|
||||
System.out.println("**************2、获取调用凭证get_wxpayface_authinfo:"+wxFacePayResp.toString());
|
||||
wxFacePayResp = weChatPayFaceService.getWxFaceAuthInfoReqMap(rawdata);
|
||||
System.out.println("**************3、获取调用凭证get_wxpayface_authinfo:" + wxFacePayResp.toString());
|
||||
}
|
||||
return Result.ok(wxFacePayResp);
|
||||
}
|
||||
@@ -96,35 +101,49 @@ public class WxpayFaceTestController {
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别getWxpayfaceCode(获取支付凭证)
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping(value = "/getWxpayfaceCode", method = RequestMethod.POST)
|
||||
public Result<WxFacePayAuthinfoResp> getWxpayfaceCode() throws Exception {
|
||||
WxFacePayAuthinfoResp wxFacePayResp0 = new WxFacePayAuthinfoResp();
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceCode","1",System.currentTimeMillis()/1000);
|
||||
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());
|
||||
|
||||
WxFacePayAuthinfoResp authinfoResp = weChatPayFaceService.doWxPayMethod(wxFacePayReq);
|
||||
System.out.println("**************4、进行人脸识别:"+authinfoResp.toString());
|
||||
|
||||
return Result.ok(authinfoResp);
|
||||
// 构建请求参数的JSON字符串
|
||||
WxFacePayReq wxFacePayReq = new WxFacePayReq("getWxpayfaceCode", "1", System.currentTimeMillis() / 1000);
|
||||
wxFacePayReq.setAuthinfo(wxFacePayResp0.getAuthinfo())
|
||||
.setOut_trade_no("")//订单流水号
|
||||
.setTotal_fee(new String("1"));
|
||||
|
||||
WxFacePayAuthinfoResp authinfoResp = weChatPayFaceService.getWxpayfaceCode(wxFacePayReq);
|
||||
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);
|
||||
} else {
|
||||
return Result.error("微信获取调用凭证失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//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<>();
|
||||
|
||||
@@ -16,14 +16,14 @@ public class WxpayFaceSDKDll {
|
||||
* 获取 Dll 实例,同时注册 Dll 控件。
|
||||
*
|
||||
* @return WxpayFaceSDKDll 实例
|
||||
* @throws WxpayFaceSDKDll.DllRegistrationException 如果注册控件失败,抛出此异常
|
||||
* @throws DllRegistrationException 如果注册控件失败,抛出此异常
|
||||
*/
|
||||
public static WxpayFaceSDKDll.Dll instance() throws DllRegistrationException {
|
||||
public static Dll instance() throws DllRegistrationException {
|
||||
try {
|
||||
return Native.load("WxpayFaceSDK", WxpayFaceSDKDll.Dll.class);
|
||||
return Native.load("WxpayFaceSDK", Dll.class);
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ public interface WeChatPayFaceService {
|
||||
/**
|
||||
* 调用方法
|
||||
* 1、程序启动时初始化initWxpayface;2、获取数据getWxpayfaceRawdata;
|
||||
* 8、更新支付结果updateWxpayfacePayResult
|
||||
* @param wxFacePayReq
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
@@ -36,7 +37,7 @@ public interface WeChatPayFaceService {
|
||||
* @Param rawData 初始化数据。由微信人脸SDK的接口返回。
|
||||
* @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 JsonProcessingException
|
||||
*/
|
||||
WxFacePayAuthinfoResp doWxPayMethod(WxFacePayReq wxFacePayReq) throws UnsupportedEncodingException, JsonProcessingException, WxpayFaceSDKDll.DllRegistrationException;
|
||||
|
||||
WxFacePayAuthinfoResp getWxpayfaceCode(WxFacePayReq wxFacePayReq) throws UnsupportedEncodingException, JsonProcessingException, WxpayFaceSDKDll.DllRegistrationException;
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.sun.jna.Memory;
|
||||
import com.sun.jna.Pointer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -27,10 +28,8 @@ public class CallWxpayFaceServiceImpl implements CallWxpayFaceService {
|
||||
}
|
||||
|
||||
//赋值
|
||||
private static WxMpProperties wxMpProperties;
|
||||
public static void setWxMpConfiguration(WxMpProperties wxMpProperties) {
|
||||
CallWxpayFaceServiceImpl.wxMpProperties = wxMpProperties;
|
||||
}
|
||||
@Autowired
|
||||
private WxMpProperties wxMpProperties;
|
||||
|
||||
|
||||
/**
|
||||
@@ -46,7 +45,7 @@ public class CallWxpayFaceServiceImpl implements CallWxpayFaceService {
|
||||
reqPointer.setString(0, reqJson);
|
||||
//请求数据长度
|
||||
int reqSize = reqPointer.getString(0).length();
|
||||
System.out.println("-----------调用微信刷脸请求数据----------"+reqPointer.getString(0));
|
||||
System.out.println("-----------调用微信刷脸DLL请求数据----------"+reqPointer.getString(0));
|
||||
|
||||
//接收响应
|
||||
long[] pRespBuf = new long[1];
|
||||
@@ -64,7 +63,7 @@ public class CallWxpayFaceServiceImpl implements CallWxpayFaceService {
|
||||
byte[] byteArray = pointer.getByteArray(0, respSize[0]);
|
||||
resStr = new String(byteArray, StandardCharsets.UTF_8);
|
||||
|
||||
System.out.println("-----------调用服务成功结果: " + resStr);
|
||||
System.out.println("-----------调用微信刷脸DLL请求结果: " + resStr);
|
||||
dll.wxpayReleaseResponse(new String[2]);
|
||||
//释放 C:\Windows\System32目录下 WxpayFaceSDK.INSTANCE.wxpayReleaseResponse(new String[2]);
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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.WxMpProperties;
|
||||
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.util.WXPayUtil;
|
||||
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.vo.WxFacePayAuthinfoResp;
|
||||
import com.dpkj.modules.scanface.wx.vo.WxFacePayMicroPayResp;
|
||||
@@ -79,7 +81,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
reqPointer.setString(0, reqJson);
|
||||
//请求数据长度
|
||||
int reqSize = reqPointer.getString(0).length();
|
||||
System.out.println("-----------调用微信刷脸请求数据----------" + reqPointer.getString(0));
|
||||
System.out.println("-----------调用微信刷脸DLL请求数据----------" + reqPointer.getString(0));
|
||||
|
||||
//接收响应
|
||||
long[] pRespBuf = new long[1];
|
||||
@@ -98,7 +100,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
byte[] byteArray = pointer.getByteArray(0, respSize[0]);
|
||||
resStr = new String(byteArray, StandardCharsets.UTF_8);
|
||||
|
||||
System.out.println("-----------调用服务成功结果: " + resStr);
|
||||
System.out.println("-----------微信刷脸DLL调用服务成功结果: " + resStr);
|
||||
//释放
|
||||
dll.wxpayReleaseResponse(new String[2]);
|
||||
|
||||
@@ -124,56 +126,66 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
* @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");
|
||||
public WxFacePayAuthinfoResp getWxFaceAuthInfoReqMap(String rawData) throws Exception {
|
||||
try {
|
||||
SortedMap<String, String> map = new TreeMap<String, String>();
|
||||
//门店编号, 由商户定义, 各门店唯一。
|
||||
map.put("store_id", WxConstant.STORE_ID);
|
||||
//门店名称,由商户定义。(可用于展示);中文会导致调用失败
|
||||
String text = WxConstant.STORE_TEXT;
|
||||
String storeName = Base64.getEncoder().encodeToString(text.getBytes());
|
||||
map.put("store_name", storeName);
|
||||
//终端设备编号,由商户定义
|
||||
map.put("device_id", WxConstant.DEVICE_ID);
|
||||
//初始化数据。由微信人脸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", WxConstant.VERSION);
|
||||
//随机字符串,不长于32位:工具类微信随机数
|
||||
map.put("nonce_str", WxRandomUtils.getNonceStr());
|
||||
//参数签名,使用MD5
|
||||
map.put("sign_type", WxConstant.SING_TYPE);
|
||||
|
||||
//加密和生成微信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);
|
||||
//加密和生成微信v2指定的xml格式
|
||||
// WXPayUtil.createSign("UTF-8",map,wxMpProperties.getMchConfig().getKeyApi());
|
||||
String sign = WXPayUtil.generateSignedXml(map, wxMpProperties.getMchConfig().getKeyApi(), WxPayConstants.SignType.MD5);
|
||||
log.info("--------3、获取调用凭证 构建微信获取刷脸授权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");
|
||||
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("--------3、获取调用凭证 发起http调用结果:{}", exchange.getBody());
|
||||
|
||||
//转成返回对象
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
WxFacePayAuthinfoResp wxFacePayAuthinfoResp = mapper.readValue(exchange.getBody(), WxFacePayAuthinfoResp.class);
|
||||
log.info("--------发起http调用结果转换", wxFacePayAuthinfoResp.toString());
|
||||
XmlParserUtil.extractAuthInfo(exchange.getBody());
|
||||
//转成map方便取值
|
||||
Map<String, String> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
log.info("------3、获取调用凭证 调用结果转换为map:{}", stringMap);
|
||||
|
||||
return stringMap;
|
||||
//转成返回对象
|
||||
WxFacePayAuthinfoResp wxFacePayAuthinfoResp = XmlUtils.mapToObject(
|
||||
stringMap,
|
||||
WxFacePayAuthinfoResp.class
|
||||
);
|
||||
log.info("--------发起http调用结果转换为WxFacePayAuthinfoResp", wxFacePayAuthinfoResp.toString());
|
||||
|
||||
return wxFacePayAuthinfoResp;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +199,14 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
* @throws JsonProcessingException
|
||||
*/
|
||||
@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字符串
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String req = mapper.writeValueAsString(wxFacePayReq);
|
||||
@@ -195,6 +214,8 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
// 创建一个Pointer来接收响应
|
||||
List<String> pResp = new ArrayList<>();
|
||||
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);
|
||||
@@ -203,7 +224,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
|
||||
|
||||
//5、进行发起订单支付
|
||||
public Map<String, Object> createWxOrder() throws Exception {
|
||||
public Map<String, String> createWxOrder() throws Exception {
|
||||
SortedMap<String, String> map = new TreeMap<String, String>();
|
||||
//微信分配的公众账号ID(企业号corpid即为此appId)
|
||||
map.put("appid", wxMpProperties.getMchConfig().getAppId());
|
||||
@@ -238,7 +259,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
String.class);
|
||||
log.info("--------5、进行发起订单支付:发起http调用结果:【{}】", exchange.getBody());
|
||||
//转成map方便取值
|
||||
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
Map<String, String> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
|
||||
//转成返回对象
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
@@ -250,7 +271,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
|
||||
|
||||
//6、查询订单状态
|
||||
public Map<String, Object> orderquery() throws Exception {
|
||||
public Map<String, String> orderquery() throws Exception {
|
||||
SortedMap<String, String> map = new TreeMap<String, String>();
|
||||
//微信支付分配的公众账号ID(企业号corpid即为此appId)
|
||||
map.put("appid", wxMpProperties.getMchConfig().getAppId());
|
||||
@@ -278,7 +299,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
String.class);
|
||||
log.info("--------6、查询订单状态,发起http调用结果:【{}】", exchange.getBody());
|
||||
//转成map方便取值
|
||||
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
Map<String, String> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
|
||||
//转成返回对象
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
@@ -290,7 +311,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
|
||||
|
||||
//7、撤销交易
|
||||
public Map<String, Object> reverse() throws Exception {
|
||||
public Map<String, String> reverse() throws Exception {
|
||||
SortedMap<String, String> map = new TreeMap<String, String>();
|
||||
//微信分配的公众账号ID(企业号corpid即为此appId)
|
||||
map.put("appid", wxMpProperties.getMchConfig().getAppId());
|
||||
@@ -317,7 +338,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService {
|
||||
String.class);
|
||||
log.info("--------7、撤销交易,发起http调用结果:【{}】", exchange.getBody());
|
||||
//转成map方便取值
|
||||
Map<String, Object> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
Map<String, String> stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml");
|
||||
|
||||
//转成返回对象
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@@ -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>节点");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
@@ -20,6 +21,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class XmlUtils {
|
||||
|
||||
|
||||
/**
|
||||
* xml解析器
|
||||
*
|
||||
@@ -32,8 +34,8 @@ public class XmlUtils {
|
||||
* @返回子节点属性值:->节点名->子节点名=>属性名:属性值
|
||||
* @返回子节点值:->节点名->子节点名:属性值
|
||||
*/
|
||||
public static Map<String, Object> xmlParser(String xml, String filterRootEleName) {
|
||||
Map<String, Object> retMap = new HashMap<>();
|
||||
public static Map<String, String> xmlParser(String xml, String filterRootEleName) {
|
||||
Map<String, String> retMap = new HashMap<>();
|
||||
//1.创建Reader对象
|
||||
try {
|
||||
SAXReader reader = new SAXReader();
|
||||
@@ -56,14 +58,14 @@ public class XmlUtils {
|
||||
* @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());
|
||||
private static void parser(Element ele, StringBuilder eleKey, String firstEleName, Map<String, String> 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() + ""));
|
||||
//builder.append("->" + ele.getName());
|
||||
if (StringUtils.isNotEmpty(StringUtils.stripToEmpty(ele.getData() + ""))) {
|
||||
retMap.put(ele.getName(), StringUtils.stripToEmpty(ele.getData() + ""));
|
||||
}
|
||||
List<Attribute> attributes = ele.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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -121,4 +121,46 @@ public class WxFacePayAuthinfoResp {
|
||||
* 用户身份信息查询凭证
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,12 @@ public class WxFacePayReq {
|
||||
*/
|
||||
private long now;
|
||||
|
||||
|
||||
/**
|
||||
* 对摄像头画面进行旋转,1为+90度,2为180度,3为-90度,
|
||||
*/
|
||||
private int camera_rotation;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:是
|
||||
@@ -54,14 +60,14 @@ public class WxFacePayReq {
|
||||
* 必填:否
|
||||
* 子商户绑定的公众号/小程序 appid(可不填)
|
||||
*/
|
||||
private String sub_appid;
|
||||
//private String sub_appid;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 子商户号(非服务商模式不填)
|
||||
*/
|
||||
private String sub_mch_id;
|
||||
//private String sub_mch_id;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
@@ -75,7 +81,7 @@ public class WxFacePayReq {
|
||||
* 必填:否
|
||||
* 通过getWxpayfaceUserInfo获取的openid,传入后可使用快捷支付模式。1.24版本以上支持该参数
|
||||
*/
|
||||
private String openid;
|
||||
//private String openid;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
@@ -119,21 +125,21 @@ public class WxFacePayReq {
|
||||
* 指定刷脸界面显示的屏幕编号。
|
||||
* 编号1为主屏幕,其余屏幕按系统设置中的顺序从2开始编号,常用场景举例:双屏机器上传"2"即可显示在副屏上。如果不填写则默认显示在主屏幕。1.18版本以上支持该参数
|
||||
*/
|
||||
private String screen_index;
|
||||
//private String screen_index;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 设置不接受外接键盘输入,可选值:"1",禁用。1.23版本以上支持该参数
|
||||
*/
|
||||
private String disable_keyboard;
|
||||
//private String disable_keyboard;
|
||||
|
||||
/**
|
||||
* 4、进行人脸识别
|
||||
* 必填:否
|
||||
* 设置刷脸窗口以无焦点方式启动,可选值:"1",无焦点启动窗口。1.26版本以上支持该参数
|
||||
*/
|
||||
private String use_window_nofocus;
|
||||
//private String use_window_nofocus;
|
||||
|
||||
|
||||
/**
|
||||
@@ -151,4 +157,13 @@ public class WxFacePayReq {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user