From 3ac2688758bfcfaa148a471d95f00da73dec53ba Mon Sep 17 00:00:00 2001
From: Jack <46790855@qq.com>
Date: Mon, 27 Jan 2025 23:21:49 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8B=89=E5=8D=A1=E6=8B=89=E6=94=AF=E4=BB=98?=
=?UTF-8?q?=E8=B0=83=E8=AF=95=E4=BF=AE=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../mall/common/utils/StringUtils.java | 52 +++++
.../suisung/mall/filter/AuthGlobalFilter.java | 1 +
.../src/main/resources/application.yml | 1 +
mall-pay/pom.xml | 7 +
.../controller/mobile/IndexController.java | 6 +
.../mall/pay/service/LakalaService.java | 10 +-
.../mall/pay/service/PayUserPayService.java | 7 +
.../pay/service/impl/LakalaServiceImpl.java | 61 ++++-
.../impl/PayConsumeDepositServiceImpl.java | 1 +
.../service/impl/PayUserPayServiceImpl.java | 208 ++++++++++++++----
.../suisung/mall/pay/utils/LakalaUtil.java | 180 +++++++++++++++
.../src/main/resources/bootstrap-prod.yml | 4 +-
.../impl/ShopStorePrinterServiceImpl.java | 61 +----
.../impl/SyncThirdDataServiceImpl.java | 2 -
14 files changed, 486 insertions(+), 115 deletions(-)
create mode 100644 mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java
diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java b/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java
index 078fa10b..baae74b8 100644
--- a/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java
+++ b/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java
@@ -1,9 +1,14 @@
package com.suisung.mall.common.utils;
import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.net.URLEncoder;
import java.security.MessageDigest;
@@ -29,6 +34,7 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
private static final String ALL_TEMP = INT_TEMP + STR_TEMP;
private static final Random RANDOM = new Random();
private static final Logger logger = LoggerFactory.getLogger(StringUtils.class);
+ private static final ObjectMapper objectMapper = new ObjectMapper();
public static void main(String[] args) {
System.out.println(removeProvinceCityDistrict("广西壮族自治区贵港市桂平市西山镇新安街粤桂花城1102号"));
@@ -223,6 +229,7 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 生成唯一码
+ *
* @param length
* @return
*/
@@ -271,6 +278,51 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils {
return fullAddress;
}
+ /**
+ * 判断字符串是否是XML或JSON格式
+ *
+ * @param input
+ * @return XML或JSON或None
+ */
+ public static String isXMLOrJSON(String input) {
+ if (input == null || input.trim().isEmpty()) {
+ return "None";
+ }
+ input = input.trim();
+
+ // 快速初步判断
+ if (input.startsWith("{") || input.startsWith("[")) {
+ if (isValidJson(input)) {
+ return "JSON";
+ }
+ } else if (input.startsWith("<")) {
+ if (isValidXml(input)) {
+ return "XML";
+ }
+ }
+ return "None";
+ }
+
+ private static boolean isValidJson(String json) {
+ try {
+ objectMapper.readTree(json);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ private static boolean isValidXml(String xml) {
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.parse(new InputSource(new StringReader(xml)));
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
/**
* 生成的随机数类型
diff --git a/mall-gateway/src/main/java/com/suisung/mall/filter/AuthGlobalFilter.java b/mall-gateway/src/main/java/com/suisung/mall/filter/AuthGlobalFilter.java
index 3c92f120..a989bd5f 100644
--- a/mall-gateway/src/main/java/com/suisung/mall/filter/AuthGlobalFilter.java
+++ b/mall-gateway/src/main/java/com/suisung/mall/filter/AuthGlobalFilter.java
@@ -42,6 +42,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
return chain.filter(exchange);
}
}
+
try {
//从token中解析用户信息并设置到Header中去
String realToken = token.replace(AuthConstant.JWT_TOKEN_PREFIX, "");
diff --git a/mall-gateway/src/main/resources/application.yml b/mall-gateway/src/main/resources/application.yml
index 321a87a4..85ece989 100644
--- a/mall-gateway/src/main/resources/application.yml
+++ b/mall-gateway/src/main/resources/application.yml
@@ -70,6 +70,7 @@ secure:
- "/admin/account/account-user-base/login"
- "/static/image/**"
- "/mobile/pay/index/notify_url"
+ #- "/mobile/pay/index/lkl_wxPay_notify_url" #拉卡拉微信支付回调
- "/mobile/pay/index/return_url"
- "/shop/static/**"
- "/mobile/shop/qrcode/getQrcode"
diff --git a/mall-pay/pom.xml b/mall-pay/pom.xml
index 9923af8f..c491acd1 100644
--- a/mall-pay/pom.xml
+++ b/mall-pay/pom.xml
@@ -79,6 +79,13 @@
+
+
+ com.github.wechatpay-apiv3
+ wechatpay-java
+ 0.2.15
+
+
org.springframework.boot
diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/controller/mobile/IndexController.java b/mall-pay/src/main/java/com/suisung/mall/pay/controller/mobile/IndexController.java
index 790ce7b8..d4f2b3e6 100644
--- a/mall-pay/src/main/java/com/suisung/mall/pay/controller/mobile/IndexController.java
+++ b/mall-pay/src/main/java/com/suisung/mall/pay/controller/mobile/IndexController.java
@@ -243,6 +243,12 @@ public class IndexController extends BaseControllerImpl {
return payUserPayService.notifyUrl(request, response, "wx_native");
}
+ @ApiOperation(value = "拉卡拉在微信回调通知", notes = "拉卡拉在微信回调通知")
+ @RequestMapping(value = "/lkl_wxPay_notify_url", method = RequestMethod.POST)
+ public String lklWxNotifyUrl(HttpServletRequest request) {
+ return payUserPayService.lklNotifyUrl(request);
+ }
+
@RequestMapping(value = "/pay_state_detection", method = RequestMethod.GET)
public CommonResult payStateDetection(@RequestParam String order_id) {
UserDto userDto = getCurrentUser();
diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaService.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaService.java
index d6df9e5f..e25be858 100644
--- a/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaService.java
+++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaService.java
@@ -10,6 +10,7 @@ package com.suisung.mall.pay.service;
import cn.hutool.json.JSONObject;
import com.suisung.mall.common.pojo.res.PayAccRespFieldsRes;
+import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -21,6 +22,13 @@ public interface LakalaService {
*/
void doInit();
+ /**
+ * 初始化微信V3支付参数
+ *
+ * @return
+ */
+ NativePayService initWxV3SDK();
+
JSONObject transPreOrder(HttpServletRequest request, HttpServletResponse response, String orderId);
/**
@@ -38,5 +46,5 @@ public interface LakalaService {
* @param remark 备注
* @return
*/
- PayAccRespFieldsRes transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark);
+ JSONObject transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark);
}
diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/PayUserPayService.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/PayUserPayService.java
index 1a0bef3e..80497017 100644
--- a/mall-pay/src/main/java/com/suisung/mall/pay/service/PayUserPayService.java
+++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/PayUserPayService.java
@@ -31,6 +31,13 @@ public interface PayUserPayService extends IBaseService {
String notifyUrl(HttpServletRequest request, HttpServletResponse response, String payment_channel_code);
+ /**
+ * lakala 支付回调
+ * @param request
+ * @return
+ */
+ String lklNotifyUrl(HttpServletRequest request);
+
void returnUrl(HttpServletRequest request, HttpServletResponse response, String payment_channel_code);
/**
diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaServiceImpl.java
index 13c844d0..d8e4ebd9 100644
--- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaServiceImpl.java
+++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaServiceImpl.java
@@ -10,6 +10,7 @@ package com.suisung.mall.pay.service.impl;
import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ijpay.core.kit.IpKit;
import com.lkl.laop.sdk.Config2;
@@ -22,24 +23,42 @@ import com.suisung.mall.common.exception.ApiException;
import com.suisung.mall.common.pojo.res.PayAccRespFieldsRes;
import com.suisung.mall.common.utils.I18nUtil;
import com.suisung.mall.pay.service.LakalaService;
+import com.wechat.pay.java.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
+
+import com.wechat.pay.java.core.Config;
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+import com.wechat.pay.java.service.payments.nativepay.NativePayService;
+import com.wechat.pay.java.service.payments.nativepay.model.Amount;
+import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
+import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
+
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.*;
+
@Slf4j
@Service
public class LakalaServiceImpl implements LakalaService {
-
private static volatile boolean init = false;
+ private static volatile NativePayService wxV3Service= null;
+
/**
* 服务地址
*/
@@ -121,6 +140,30 @@ public class LakalaServiceImpl implements LakalaService {
return LKLSDK.init(config);
}
+ @Override
+ public NativePayService initWxV3SDK() {
+ if (wxV3Service!=null) {
+ return wxV3Service;
+ }
+
+ Config config =
+ new RSAAutoCertificateConfig.Builder()
+ .merchantId("1684833481")
+ .privateKey(getResourceFile("payKey/wx/apiclient_key.pem"))
+ .privateKeyFromPath("privateKeyPath")
+ .merchantSerialNumber("30314B93B394352C6A4616B7611C23402041ADE2")
+ .apiV3Key("n8tgyMKKAov9lVJuczMOLUjXr5IeZjce")
+ .build();
+ // 构建service
+ NativePayService service = new NativePayService.Builder().config(config).build();
+ if(service==null){
+ throw new ApiException(I18nUtil._("微信SDKV3初始化失败!"));
+ }
+
+ wxV3Service = service;
+ return service;
+ }
+
@Override
public cn.hutool.json.JSONObject transPreOrder(HttpServletRequest request, HttpServletResponse response, String orderId) {
// 1. 配置初始化
@@ -157,7 +200,7 @@ public class LakalaServiceImpl implements LakalaService {
//4. 响应
return JSONUtil.parseObj(responseStr);
} catch (SDKException e) {
- log.error("transPreOrder error", e);
+ LakalaServiceImpl.log.error("transPreOrder error", e);
throw new ApiException(I18nUtil._("获取公众号绑定信息失败!"), e);
}
@@ -177,9 +220,9 @@ public class LakalaServiceImpl implements LakalaService {
* @param requestIP 请求ip
* @param remark 备注
* @return
- * */
+ */
@Override
- public PayAccRespFieldsRes transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark) {
+ public JSONObject transPreOrder(String merchantNo, String termNo, String xcxAppId, String openId, String orderId, String subject, String totalAmount, String notifyURL, String requestIP, String remark) {
// 1. 配置初始化
doInit();
@@ -218,20 +261,24 @@ public class LakalaServiceImpl implements LakalaService {
v3LabsTransPreorderWechatReq.setAccBusiFields(wechatBus);
try {
+ log.info("拉卡拉预下单请求参数:{}", JSONUtil.toJsonStr(v3LabsTransPreorderWechatReq));
+
//3. 发送请求
String responseStr = LKLSDK.httpPost(v3LabsTransPreorderWechatReq);
+ log.info("拉卡拉预下单响应数据:{}", responseStr);
if (StrUtil.isBlank(responseStr)) {
return null;
}
- PayAccRespFieldsRes res = JSONUtil.parseObj(responseStr).get("acc_resp_fields", PayAccRespFieldsRes.class);
+ JSONObject res = JSONUtil.parseObj(responseStr);
+
//4. 响应
return res;
} catch (SDKException e) {
log.error("拉卡拉支付出错:", e);
- throw new ApiException(I18nUtil._("支付失败:"), e);
+ throw new ApiException(I18nUtil._("支付失败!"), e);
}
-
}
+
}
diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeDepositServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeDepositServiceImpl.java
index 5025f5c2..bf7aea60 100644
--- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeDepositServiceImpl.java
+++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeDepositServiceImpl.java
@@ -203,6 +203,7 @@ public class PayConsumeDepositServiceImpl extends BaseServiceImpl params = UnifiedOrderModel.builder()
- .appid(field.getApp_id())
- .mch_id(field.getSub_mch_id())
- .openid(openId)
- .out_trade_no(out_trade_no)
- .total_fee(total_fee) // 订单总金额,单位为分
- .notify_url(notifyUrl)
- .trade_type(TradeType.JSAPI.getTradeType())
- .spbill_create_ip(requestIP)
- .time_start(DateUtil.format(new Date(), "yyyyMMddHHmmss"))
- .nonce_str(field.getNonce_str())
- .body(subject) // 商品描述
- .goods_tag(trade_remark)// 订单优惠标记
- .attach("") //自定义数据说明
- .build()
- .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
-
- String xmlResult = WxPayApi.pushOrder(false, params);
- Map resultMap = WxPayKit.xmlToMap(xmlResult);
- String returnCode = resultMap.get("return_code");
- String returnMsg = resultMap.get("return_msg");
-
+// logger.info("拉卡拉预支付返回参数:{}", JSONUtil.toJsonStr(field));
Map data = new HashMap();
data.put("code", 1);
data.put("data", new Object());
- data.put("message", returnMsg);
- if (!WxPayKit.codeIsOk(returnCode)) {
+ if (lakalaRespJSON == null || !lakalaRespJSON.getStr("code").equals("BBS00000")) {
+ data.put("message", lakalaRespJSON.getStr("msg"));
setResponseBody(response, data);
return;
}
- String resultCode = resultMap.get("result_code");
- if (!WxPayKit.codeIsOk(resultCode)) {
- setResponseBody(response, data);
- return;
- }
-
- // 预支付订单 Id
- String prepayId = resultMap.get("prepay_id");
- Map packageParams = Convert.toMap(String.class, Object.class, WxPayKit.prepayIdCreateSign(prepayId, appId, wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256));
- data.put("status", 200);
+ // 统一下单请求参数构建
+ cn.hutool.json.JSONObject field = (cn.hutool.json.JSONObject) lakalaRespJSON.getByPath("resp_data.acc_resp_fields");
+ Map params = new HashMap();
+ params.put("package", "prepay_id=" + field.getStr("prepay_id"));
+ params.put("nonceStr", field.getStr("nonce_str"));
+ params.put("timeStamp", field.getStr("time_stamp"));
+ params.put("paySign", field.getStr("pay_sign"));
+ params.put("signType", field.getStr("sign_type"));
+ params.put("appId", field.getStr("app_id"));
Map result = new HashMap();
- result.put("data", packageParams);
+ result.put("data", params);
result.put("statusCode", 200);
+
+ data.put("status", 200);
data.put("data", result);
+ data.put("message", "OK");
+
+ logger.info("拉卡拉调起支付的参数:{}", JSONUtil.toJsonStr(data));
+
setResponseBody(response, data);
}
@@ -1145,8 +1133,10 @@ public class PayUserPayServiceImpl extends BaseServiceImpl params = new HashMap<>();
if (ObjectUtil.equal("wx_native", payment_channel_code)) {
- String xmlMsg = HttpKit.readData(request);
- params = WxPayKit.xmlToMap(xmlMsg);
+
+ String dataStr = HttpKit.readData(request);
+
+ params = WxPayKit.xmlToMap(dataStr);
trade_type = params.get("trade_type");
order_id = params.get("out_trade_no");
}
@@ -1200,7 +1190,7 @@ public class PayUserPayServiceImpl extends BaseServiceImpl params;
+ try {
+ lakalaService.doInit();
+
+ // spring-boot 2.x 直接调用读取请求体并验签方法,返回请求体
+ String body = LKLSDK.notificationHandle(request);
+ if (StrUtil.isBlank(body)) {
+ return lklNotifyMsg(false, "验签失败!");
+ }
+ // logger.debug("支付回调 body 数据:{}", body);
+
+ // 拉卡拉返回 json 格式的 数据
+ params = Convert.toMap(String.class, String.class, JSONUtil.parseObj(body));
+ String order_id = getParameter("out_trade_no");
+ if(StrUtil.isBlank(order_id)){
+ order_id = params.getOrDefault("out_trade_no","");
+ }
+ logger.debug("支付回调 params 数据:{}", params);
+
+ String authorization = request.getHeader("Authorization");
+// logger.debug("支付回调 Authorization 数据:{}", authorization);
+ Map authMap = LakalaUtil.getLakalaAuthorizationMap(authorization);
+ if (authMap != null && authMap.get("signature") != null) {
+ params.put("sign", authMap.get("signature"));
+ }
+
+ // 基于安全考虑,检测支付模式及数据
+ // 判断是门店 店铺 平台
+ Integer payment_store_id = 0;
+ Integer payment_chain_id = 0;
+ if (!accountBaseConfigService.getTradeModePlantform()) {
+ // 不可以联合支付。
+ QueryWrapper tradeQueryWrapper = new QueryWrapper<>();
+ tradeQueryWrapper.eq("order_id", order_id);
+ PayConsumeTrade trade_row_tmp = payConsumeTradeService.findOne(tradeQueryWrapper);
+
+ // 固定死, 是门店收银还是店铺收银。, 统一店铺收银
+ payment_store_id = trade_row_tmp.getStore_id();
+ }
+
+ QueryWrapper channelQueryWrapper = new QueryWrapper<>();
+ channelQueryWrapper.eq("payment_channel_code", "lakala");
+ PayPaymentChannel payPaymentChannel = payPaymentChannelService.findOne(channelQueryWrapper);
+ Integer payment_channel_id = payPaymentChannel.getPayment_channel_id();
+
+ // 插入充值记录
+
+ PayConsumeDeposit notify_row = createNotify(params, payPaymentChannel);
+ notify_row.setOrder_id(order_id);
+ notify_row.setStore_id(payment_store_id); // 所属店铺
+ notify_row.setChain_id(payment_chain_id); // 所属门店
+ notify_row.setPayment_channel_id(payment_channel_id);
+
+ BigDecimal zero = BigDecimal.ZERO;
+
+ // 判断是否联合支付
+ PayConsumeTradeCombine tradeCombine = payConsumeTradeCombineService.get(order_id);
+ TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
+ try {
+ if (tradeCombine != null && StrUtil.isNotBlank(tradeCombine.getOrder_ids())) {
+ notify_row.setOrder_id(tradeCombine.getOrder_ids());
+ }
+
+ if (!payConsumeDepositService.processDeposit(notify_row, zero, zero, zero, zero, zero)) {
+ log.error("支付失败!");
+ return lklNotifyMsg(false, "支付失败!");
+ }
+
+ transactionManager.commit(transactionStatus);
+ } catch (Exception e) {
+ transactionManager.rollback(transactionStatus);
+ log.error("支付失败,错误信息:", e);
+ throw new ApiException(e.getMessage());
+ }
+
+ return lklNotifyMsg(true, "");
+
+ } catch (Exception e) {
+ logger.error("验签发生异常:" + e.getMessage() + ", {}", e);
+ return lklNotifyMsg(false, "验签发生异常!");
+ }
+ }
+
/**
* 获取支付异步请求返回值(多种支付方式)
*
@@ -1288,6 +1364,13 @@ public class PayUserPayServiceImpl extends BaseServiceImpl retData = new HashMap<>();
+ retData.put("code", code ? "SUCCESS" : "FAIL");
+ retData.put("message", message);
+ return JSONUtil.toJsonStr(retData);
+ }
+
/**
* 创建支付回调参数对象
@@ -1319,6 +1402,9 @@ public class PayUserPayServiceImpl extends BaseServiceImpl params, Integer payment_channel_id, PayConsumeDeposit notify_row) {
+ BigDecimal deposit_total_fee = NumberUtil.div(Convert.toBigDecimal(params.get("total_amount")), 100);
+ String deposit_sign = ObjectUtil.defaultIfNull(params.get("sign"), "");
+ Date deposit_gmt_payment = Convert.toDate(params.get("trade_time"), new Date());
+
+ notify_row.setDeposit_trade_no(params.get("trade_no"));
+ notify_row.setOrder_id(params.get("out_trade_no"));
+ notify_row.setDeposit_quantity(1);
+ notify_row.setDeposit_seller_id(params.get("sub_mch_id"));
+ notify_row.setDeposit_is_total_fee_adjust(0);
+ notify_row.setDeposit_total_fee(deposit_total_fee);
+ notify_row.setDeposit_price(BigDecimal.ZERO);
+ notify_row.setDeposit_buyer_id(params.get("user_id2"));// openid
+ notify_row.setDeposit_gmt_payment(deposit_gmt_payment);
+ notify_row.setDeposit_service("JSAPI");
+ notify_row.setDeposit_sign(deposit_sign);
+ notify_row.setDeposit_sign_type("SHA256withRSA");
+ notify_row.setDeposit_extra_param(JSONUtil.toJsonStr(notify_row));
+ notify_row.setPayment_channel_id(payment_channel_id);
+
+ notify_row.setDeposit_payment_type(StateCode.PAYMENT_TYPE_ONLINE);
+ notify_row.setDeposit_notify_time(new Date());
}
/**
diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java b/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java
new file mode 100644
index 00000000..1af21c53
--- /dev/null
+++ b/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
+ * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
+ * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
+ * Vestibulum commodo. Ut rhoncus gravida arcu.
+ */
+
+package com.suisung.mall.pay.utils;
+
+import cn.hutool.core.util.StrUtil;
+import com.suisung.mall.common.exception.ApiException;
+import com.suisung.mall.common.utils.I18nUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.io.ClassPathResource;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.*;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+public class LakalaUtil {
+
+ /**
+ * 读取证书文件内容
+ *
+ * @param fileName recource 文件夹下的路径,如:palyKey/wx/lakala_public_key.cer
+ * @return
+ */
+ public static String getResourceFile(String fileName) {
+ StringBuilder stringBuilder = new StringBuilder();
+ try (InputStream inputStream = new ClassPathResource(fileName).getInputStream();
+ InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
+ BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ stringBuilder.append(line).append("\n");
+ }
+ String content = stringBuilder.toString();
+ // log.info("证书内容:{}", content);
+ return content;
+ } catch (IOException e) {
+ // 记录异常信息
+ log.error(e.getMessage());
+ return "";
+ }
+ }
+
+ /**
+ * 获取 body 请求数据
+ *
+ * @param request
+ * @return
+ */
+ public static String getBody(HttpServletRequest request) {
+ InputStreamReader in = null;
+ try {
+ in = new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8);
+ StringBuffer bf = new StringBuffer();
+ int len;
+ char[] chs = new char[1024];
+ while ((len = in.read(chs)) != -1) {
+ bf.append(new String(chs, 0, len));
+ }
+ return bf.toString();
+ } catch (Exception e) {
+ log.error("请求头部取数据异常:{}", e);
+ throw new ApiException(I18nUtil._("获取请求数据失败!"), e);
+ } finally {
+ if (null != in) {
+ try {
+ in.close();
+ } catch (Exception e) {
+ log.error("流关闭异常:{}", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * 获取证书信息
+ * @param inputStream
+ * @return
+ */
+ public static X509Certificate loadCertificate(InputStream inputStream) {
+ try {
+ CertificateFactory cf = CertificateFactory.getInstance("X509");
+ X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
+ String publicKeyBase64 = Base64.encodeBase64String(cert.getPublicKey().getEncoded());
+ System.out.println(publicKeyBase64);
+ cert.checkValidity();
+ return cert;
+ } catch (CertificateExpiredException e) {
+ throw new RuntimeException("证书已过期", e);
+ } catch (CertificateNotYetValidException e) {
+ throw new RuntimeException("证书尚未生效", e);
+ } catch (CertificateException e) {
+ throw new RuntimeException("无效的证书", e);
+ }
+ }
+
+
+ /**
+ * 签名验证
+ * @param certificate
+ * @param message
+ * @param signature
+ * @return
+ */
+ public static boolean verify(X509Certificate certificate, byte[] message, String signature) {
+ try {
+ Signature sign = Signature.getInstance("SHA256withRSA");
+ sign.initVerify(certificate);
+ sign.update(message);
+ byte[] signatureB = Base64.decodeBase64(signature);
+ return sign.verify(signatureB);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
+ } catch (SignatureException e) {
+ throw new RuntimeException("签名验证过程发生了错误", e);
+ } catch (InvalidKeyException e) {
+ throw new RuntimeException("无效的证书", e);
+ }
+ }
+
+ /**
+ * 解析请求头中的认证签名等信息
+ * 参考:https://o.lakala.com/#/home/document/detail?id=36
+ * @param authorization 格式如下
+ * LKLAPI-SHA256withRSA timestamp="1643271327",
+ * nonce_str="rQCbASKattHx",
+ * signature="
+ * iPSycbakMt7AgjmwbtaweDVI/RLsQnGvOGiVM93haFkPpT/BxUprYx/GKFLQZebSQMvBfbeWinmnOJlqd3bXgye41BUAVmbItSTOzaQhNyS2kbDwXXGJWmT84aeJWHUB05BWB8ng
+ * /+X7jrPtsenC6aO7Xgh8jNylJlkU59TKCi7BPGbyHo6pAWJl/Bus0IQps1ay+Eo6Ks3Ins3COV7
+ * /lmu5p5FD7TAZsfP+ZvMFObLJOrDQeBTMFKFFWj4ZkjNzNlQqZWlfLv4yLns
+ * /dKTDLDy5tRO5zwunW+li5YLcwOVf3tbevNFtg53WoBhQnwf838WNvY9zfRhOpCc4fBlWAA=="
+ *
+ * @return
+ */
+ public static Map getLakalaAuthorizationMap(String authorization) {
+ Map map = new HashMap();
+ authorization = authorization.trim();
+ int bpos = authorization.indexOf(" ");
+ String authType = authorization.substring(0, bpos);
+ String[] typeArr = authType.split("-");
+ if (typeArr.length > 1) {
+ map.put("signSystemCode", typeArr[0]);
+ map.put("signAlgorithm", typeArr[1]);
+ }
+
+ String signInfo = authorization.substring(bpos + 1);
+ String[] infoArr = signInfo.split(",");
+ String[] var7 = infoArr;
+ int var8 = infoArr.length;
+
+ for(int var9 = 0; var9 < var8; ++var9) {
+ String info = var7[var9];
+ if (info.contains("=")) {
+ int fpos = info.indexOf("=");
+ String value = info.substring(fpos + 1).trim();
+ value = value.substring(1, value.length() - 1);
+ map.put(info.substring(0, fpos).trim(), value);
+ }
+ }
+
+ return map;
+ }
+}
diff --git a/mall-pay/src/main/resources/bootstrap-prod.yml b/mall-pay/src/main/resources/bootstrap-prod.yml
index 258c1593..1cc01fd4 100644
--- a/mall-pay/src/main/resources/bootstrap-prod.yml
+++ b/mall-pay/src/main/resources/bootstrap-prod.yml
@@ -117,8 +117,6 @@ lakala:
server_url: https://s2.lakala.com
#应用Id
app_id: OP10000439
- #商户号
- merchant_no: 8226330599900LN
#商户证书序列号
serial_no: 1737359895636
#商户证书
@@ -127,5 +125,7 @@ lakala:
api_pri_key_path: payKey/lakala/prod/api_private_key.pem
#拉卡拉平台证书
lkl_platform_cer_path: payKey/lakala/prod/lkl_platform.cer
+ #商户号
+ merchant_no: 8226330599900LN
#终端号码,M0780629(B2B收银台) M0780798(专业化扫码)
term_no: M0780798
diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStorePrinterServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStorePrinterServiceImpl.java
index 79bd93f9..b2fcec4f 100644
--- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStorePrinterServiceImpl.java
+++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStorePrinterServiceImpl.java
@@ -131,45 +131,9 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl 0) {
- // 打印机已经存在的情况
-// if (existRecord.getFlag() == CommonConstant.Disable2) {
-// // 打印机没有绑定飞鹅平台
-// UpdateWrapper updateWrapper = new UpdateWrapper();
-// updateWrapper.eq("printer_id", existRecord.getPrinter_id());
-// updateWrapper.set("updated_by", userId);
-// updateWrapper.set("updated_at", new Date());
-//
-// // 往厂商添加打印机
-// // "922441475#r6ZXPvHH#核销柜台";
-// boolean success = feieUtil.addPrinter(String.format("%s#%s#%s", existRecord.getPrinter_sn(), existRecord.getPrinter_key(), existRecord.getPrinter_name()));
-// if (success) {
-// updateWrapper.set("flag", CommonConstant.Enable);
-// }
-//
-// update(updateWrapper);
-// String msg = "添加成功";
-// if (!success) {
-// msg = msg + ",但未绑定成功,请检查打印机编号和密钥是否正确。";
-// }
-//
-// return CommonResult.success(null, msg);
-// }
-
return CommonResult.success(null, "打票机已添加,请勿重复操作");
}
-// String msg = "添加成功";
- // 往厂商添加打印机
- // "922441475#r6ZXPvHH#核销柜台";
-// boolean success = feieUtil.addPrinter(String.format("%s#%s#%s", record.getPrinter_sn(), record.getPrinter_key(), record.getPrinter_name()));
-// if (success) {
-//
-// if (!success) {
-// msg = msg + ",但打印机绑定未成功,请检查打印机编号和密钥是否正确。";
-// }
-// record.setFlag(CommonConstant.Enable);
-// }
-
if (add(record)) {
return CommonResult.success(null, "添加成功");
}
@@ -220,19 +184,6 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl queryWrapper2 = new QueryWrapper<>();
@@ -364,14 +315,14 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl binding = shopOrderBaseService.getOrderPrintInfo(orderId, StateCode.ORDER_PAID_STATE_YES);
if (binding == null) {
- logger.info("订单{}信息无法获取,无法打印小票。", orderId);
+ logger.error("订单{}信息无法获取,无法打印小票。", orderId);
return false;
}
@@ -380,7 +331,7 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl printerList = selectPrinterList(storeId);
if (CollUtil.isEmpty(printerList)) {
// 店铺没有打印机,不再往下执行打印工作
- logger.info("店铺{}未添加打票机,无法打印小票。", storeId);
+ logger.error("店铺{}未添加打票机,无法打印小票。", storeId);
return false;
}
@@ -388,14 +339,14 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl> respList = feieUtil.printContentByList(printerSnList, printContent);
if (respList == null || CollUtil.isEmpty(respList)) {
// 只需一台打印机能打印,就算成功了
- logger.info("订单{}信息打印,调用飞鹅打印机打印失败。", orderId);
+ logger.error("订单{}信息打印,调用飞鹅打印机打印失败。", orderId);
return false;
}
diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java
index f18bfb15..cf0565cc 100644
--- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java
+++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java
@@ -179,8 +179,6 @@ public class SyncThirdDataServiceImpl implements SyncThirdDataService {
}
}
- // 处理商品类型
-
}
ShopBaseProductCategory productCategoryTemp = productCategoryService.getCategoryByName(list.get(i).getParent_id(), list.get(i).getCategory_name(), list.get(i).getStore_id());