From 7fc983903811670323533631e61423e969ec1e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E9=9B=AA?= <1044122544@qq.com> Date: Fri, 30 May 2025 17:39:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=88=B7=E8=84=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dpkj/common/constant/WxConstant.java | 42 ++ .../wx/controller/WxFacePayController.java | 467 ++++++++++++++++++ .../controller/WxpayFaceTestController.java | 81 +-- .../scanface/wx/dll/WxpayFaceSDKDll.java | 8 +- .../wx/service/WeChatPayFaceService.java | 6 +- .../impl/CallWxpayFaceServiceImpl.java | 11 +- .../impl/WeChatPayFaceServiceImpl.java | 131 ++--- .../scanface/wx/util/XmlParserUtil.java | 45 ++ .../modules/scanface/wx/util/XmlUtils.java | 43 +- .../modules/scanface/wx/vo/WxFaceOrderVo.java | 43 ++ .../scanface/wx/vo/WxFacePayAuthinfoResp.java | 42 ++ .../modules/scanface/wx/vo/WxFacePayReq.java | 27 +- 12 files changed, 834 insertions(+), 112 deletions(-) create mode 100644 src/main/java/com/dpkj/common/constant/WxConstant.java create mode 100644 src/main/java/com/dpkj/modules/scanface/wx/controller/WxFacePayController.java create mode 100644 src/main/java/com/dpkj/modules/scanface/wx/util/XmlParserUtil.java create mode 100644 src/main/java/com/dpkj/modules/scanface/wx/vo/WxFaceOrderVo.java diff --git a/src/main/java/com/dpkj/common/constant/WxConstant.java b/src/main/java/com/dpkj/common/constant/WxConstant.java new file mode 100644 index 0000000..5799d96 --- /dev/null +++ b/src/main/java/com/dpkj/common/constant/WxConstant.java @@ -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"; +} diff --git a/src/main/java/com/dpkj/modules/scanface/wx/controller/WxFacePayController.java b/src/main/java/com/dpkj/modules/scanface/wx/controller/WxFacePayController.java new file mode 100644 index 0000000..ee0f1b0 --- /dev/null +++ b/src/main/java/com/dpkj/modules/scanface/wx/controller/WxFacePayController.java @@ -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 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 result = (Map) 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 result = (Map) 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 result = (Map) 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 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); + } +*/ +} diff --git a/src/main/java/com/dpkj/modules/scanface/wx/controller/WxpayFaceTestController.java b/src/main/java/com/dpkj/modules/scanface/wx/controller/WxpayFaceTestController.java index d7e53c1..c67c878 100644 --- a/src/main/java/com/dpkj/modules/scanface/wx/controller/WxpayFaceTestController.java +++ b/src/main/java/com/dpkj/modules/scanface/wx/controller/WxpayFaceTestController.java @@ -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 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 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> getWxpayfaceAuthinfo() throws Exception { - Map wxFacePayResp = new HashMap<>(); + public Result 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 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 algorithms = new TreeSet<>(); diff --git a/src/main/java/com/dpkj/modules/scanface/wx/dll/WxpayFaceSDKDll.java b/src/main/java/com/dpkj/modules/scanface/wx/dll/WxpayFaceSDKDll.java index 295f6c5..4ed974d 100644 --- a/src/main/java/com/dpkj/modules/scanface/wx/dll/WxpayFaceSDKDll.java +++ b/src/main/java/com/dpkj/modules/scanface/wx/dll/WxpayFaceSDKDll.java @@ -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); } } diff --git a/src/main/java/com/dpkj/modules/scanface/wx/service/WeChatPayFaceService.java b/src/main/java/com/dpkj/modules/scanface/wx/service/WeChatPayFaceService.java index 7063b1e..69fa423 100644 --- a/src/main/java/com/dpkj/modules/scanface/wx/service/WeChatPayFaceService.java +++ b/src/main/java/com/dpkj/modules/scanface/wx/service/WeChatPayFaceService.java @@ -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 */ - Map 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; } diff --git a/src/main/java/com/dpkj/modules/scanface/wx/service/impl/CallWxpayFaceServiceImpl.java b/src/main/java/com/dpkj/modules/scanface/wx/service/impl/CallWxpayFaceServiceImpl.java index 79dce3a..d5ce7d9 100644 --- a/src/main/java/com/dpkj/modules/scanface/wx/service/impl/CallWxpayFaceServiceImpl.java +++ b/src/main/java/com/dpkj/modules/scanface/wx/service/impl/CallWxpayFaceServiceImpl.java @@ -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 { diff --git a/src/main/java/com/dpkj/modules/scanface/wx/service/impl/WeChatPayFaceServiceImpl.java b/src/main/java/com/dpkj/modules/scanface/wx/service/impl/WeChatPayFaceServiceImpl.java index f2bbfc7..757dccd 100644 --- a/src/main/java/com/dpkj/modules/scanface/wx/service/impl/WeChatPayFaceServiceImpl.java +++ b/src/main/java/com/dpkj/modules/scanface/wx/service/impl/WeChatPayFaceServiceImpl.java @@ -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 */ @Override - public Map getWxFaceAuthInfoReqMap(String rawData) throws Exception { - SortedMap map = new TreeMap(); - //门店编号, 由商户定义, 各门店唯一。 - 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 map = new TreeMap(); + //门店编号, 由商户定义, 各门店唯一。 + 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 stringHttpEntity = new HttpEntity(sign, headers); - RestTemplate restTemplate = new RestTemplate(); - //发起http调用 - ResponseEntity exchange = restTemplate.exchange(WechatUrlConfig.GET_WXPAYFACE_AUTHINFO, - HttpMethod.POST, - stringHttpEntity, - String.class); - log.info("--------发起http调用结果:【{}】", exchange.getBody()); - //转成map方便取值 - Map stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); + HttpHeaders headers = new HttpHeaders(); + HttpEntity stringHttpEntity = new HttpEntity(sign, headers); + RestTemplate restTemplate = new RestTemplate(); + //发起http调用 + ResponseEntity 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 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 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 createWxOrder() throws Exception { + public Map createWxOrder() throws Exception { SortedMap map = new TreeMap(); //微信分配的公众账号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 stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); + Map stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); //转成返回对象 ObjectMapper mapper = new ObjectMapper(); @@ -250,7 +271,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService { //6、查询订单状态 - public Map orderquery() throws Exception { + public Map orderquery() throws Exception { SortedMap map = new TreeMap(); //微信支付分配的公众账号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 stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); + Map stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); //转成返回对象 ObjectMapper mapper = new ObjectMapper(); @@ -290,7 +311,7 @@ public class WeChatPayFaceServiceImpl implements WeChatPayFaceService { //7、撤销交易 - public Map reverse() throws Exception { + public Map reverse() throws Exception { SortedMap map = new TreeMap(); //微信分配的公众账号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 stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); + Map stringMap = XmlUtils.xmlParser(exchange.getBody(), "xml"); //转成返回对象 ObjectMapper mapper = new ObjectMapper(); diff --git a/src/main/java/com/dpkj/modules/scanface/wx/util/XmlParserUtil.java b/src/main/java/com/dpkj/modules/scanface/wx/util/XmlParserUtil.java new file mode 100644 index 0000000..fe5d4e9 --- /dev/null +++ b/src/main/java/com/dpkj/modules/scanface/wx/util/XmlParserUtil.java @@ -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表达式定位节点 + 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("未找到节点"); + } + } + +} diff --git a/src/main/java/com/dpkj/modules/scanface/wx/util/XmlUtils.java b/src/main/java/com/dpkj/modules/scanface/wx/util/XmlUtils.java index a01e581..3445552 100644 --- a/src/main/java/com/dpkj/modules/scanface/wx/util/XmlUtils.java +++ b/src/main/java/com/dpkj/modules/scanface/wx/util/XmlUtils.java @@ -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 xmlParser(String xml, String filterRootEleName) { - Map retMap = new HashMap<>(); + public static Map xmlParser(String xml, String filterRootEleName) { + Map 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 retMap) { - StringBuilder builder = new StringBuilder(eleKey.toString()); + private static void parser(Element ele, StringBuilder eleKey, String firstEleName, Map 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 attributes = ele.attributes(); for (Attribute attribute : attributes) { @@ -82,4 +84,31 @@ public class XmlUtils { } + /** + * 通用方法:将Map转换为Java对象 + */ + public static T mapToObject(Map map, Class 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; + } + } diff --git a/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFaceOrderVo.java b/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFaceOrderVo.java new file mode 100644 index 0000000..204e17b --- /dev/null +++ b/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFaceOrderVo.java @@ -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; + +} diff --git a/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFacePayAuthinfoResp.java b/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFacePayAuthinfoResp.java index d6153ed..25af81b 100644 --- a/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFacePayAuthinfoResp.java +++ b/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFacePayAuthinfoResp.java @@ -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; } diff --git a/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFacePayReq.java b/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFacePayReq.java index 0bf421f..d6e868c 100644 --- a/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFacePayReq.java +++ b/src/main/java/com/dpkj/modules/scanface/wx/vo/WxFacePayReq.java @@ -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; + } + + }