Java对接拉卡拉支付完整指南(附详细代码)

 更新时间:2026年03月26日 09:00:39   作者:crispsea  
拉卡拉支付SDK是一个面向Java开发者的支付解决方案,其设计目的是为了帮助开发者在Java环境中轻松集成拉卡拉的支付功能,这篇文章主要介绍了Java对接拉卡拉支付的相关资料,需要的朋友可以参考下

概述

拉卡拉支付是中国领先的第三方支付解决方案提供商。本文档详细介绍如何在Java Spring Boot项目中集成拉卡拉支付SDK,实现收银台订单创建和支付回调处理功能。

功能特性

  • ✅ 收银台订单创建(全报文加密)
  • ✅ 支付回调通知处理
  • ✅ 签名验证
  • ✅ 订单状态管理

1.环境准备

接入官方sdk

  <!--         拉卡拉支付依赖-->
        <dependency>
            <groupId>com.lkl.laop.sdk</groupId>
            <artifactId>lkl-laop-java-sdk</artifactId>
            <version>1.0.8</version>
            <systemPath>${project.basedir}/src/main/resources/lib/lkl-java-sdk-1.0.8.jar</systemPath>
            <scope>system</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.3</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.68</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.68</version>
        </dependency>

导入依赖 然后根据sdk写文档拉起支付

2. 证书准备

需要从拉卡拉官方获取以下证书文件:

  • 商户私钥证书(PEM格式)
  • 拉卡拉平台证书(PEM格式)
  • 拉卡拉平台通知证书(PEM格式)

SDK初始化配置

1. 配置文件 (application.yml)

application.yml 中添加拉卡拉支付配置:

# 拉卡拉支付SDK配置
lakala:
  sdk:
    # 拉卡拉应用ID
    app-id: "OP00000003"
    # 商户证书序列号
    serial-no: "dfba8194c41b84cf"
    # 商户私钥(PEM格式字符串)
    private-key: |
      -----BEGIN PRIVATE KEY-----
      MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDvDBZyHUDndAGx
      rIcsCV2njhNO3vCEZotTaWYSYwtDvkcAb1EjsBFabXZaKigpqFXk5XXNI3NIHP9M
      ...(私钥内容)
      -----END PRIVATE KEY-----
    # 拉卡拉平台证书(用于验证API响应签名)
    lkl-certificate: |
      -----BEGIN CERTIFICATE-----
      MIIEMTCCAxmgAwIBAgIGAXRTgcMnMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNVBAYT
      ...(平台证书内容)
      -----END CERTIFICATE-----
    # 拉卡拉平台通知证书(用于验证异步通知签名)
    lkl-notify-certificate: |
      -----BEGIN CERTIFICATE-----
      MIIEMTCCAxmgAwIBAgIGAXRTgcMnMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNVBAYT
      ...(通知证书内容)
      -----END CERTIFICATE-----
    # SM4加密密钥(Base64编码)
    sm4-key: "LHo55AjrT4aDhAIBZhb5KQ=="
    # API服务器地址
    server-url: "https://test.wsmsd.cn/sit"
    # 连接超时时间(毫秒)
    connect-timeout: 50000
    # 读取超时时间(毫秒)
    read-timeout: 100000
    # Socket超时时间(毫秒)
    socket-timeout: 50000

2. SDK初始化类 (LakalaSdkConfig.java)

创建SDK初始化配置类:

package com.shunp.framework.config;
import com.laop.sdk.Config2;
import com.laop.sdk.LKLSDK;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
 * 拉卡拉SDK配置类
 */
@Configuration
@Slf4j
public class LakalaSdkConfig {
    @Value("${lakala.sdk.app-id:}")
    private String appId;
    @Value("${lakala.sdk.serial-no:}")
    private String serialNo;
    @Value("${lakala.sdk.private-key:}")
    private String privateKey;
    @Value("${lakala.sdk.lkl-certificate:}")
    private String lklCertificate;
    @Value("${lakala.sdk.lkl-notify-certificate:}")
    private String lklNotifyCertificate;
    @Value("${lakala.sdk.sm4-key:}")
    private String sm4Key;
    @Value("${lakala.sdk.server-url:}")
    private String serverUrl;
    @Value("${lakala.sdk.connect-timeout:50000}")
    private Integer connectTimeout;
    @Value("${lakala.sdk.read-timeout:100000}")
    private Integer readTimeout;
    @Value("${lakala.sdk.socket-timeout:50000}")
    private Integer socketTimeout;
    /**
     * 初始化LKLSDK
     */
    @PostConstruct
    public void initLklSdk() {
        try {
            log.info("开始初始化拉卡拉SDK...");
            // 校验必要参数
            if (appId == null || appId.trim().isEmpty()) {
                log.warn("拉卡拉SDK appId未配置,跳过初始化");
                return;
            }
            // ... 其他参数校验
            // 创建Config2对象
            Config2 config = new Config2();
            config.setAppId(appId.trim());
            config.setSerialNo(serialNo.trim());
            config.setPriKey(privateKey.trim());
            config.setLklCer(lklCertificate.trim());
            config.setLklNotifyCer(lklNotifyCertificate.trim());
            config.setServerUrl(serverUrl.trim());
            // 可选参数
            if (sm4Key != null && !sm4Key.trim().isEmpty()) {
                config.setSm4Key(sm4Key.trim());
            }
            if (connectTimeout != null) {
                config.setConnectTimeout(connectTimeout);
            }
            if (readTimeout != null) {
                config.setReadTimeout(readTimeout);
            }
            if (socketTimeout != null) {
                config.setSocketTimeout(socketTimeout);
            }
            // 初始化SDK
            boolean initResult = LKLSDK.init(config);
            if (initResult) {
                log.info("拉卡拉SDK初始化成功,appId: {}", appId);
            } else {
                log.error("拉卡拉SDK初始化失败,appId: {}", appId);
            }
        } catch (Exception e) {
            log.error("拉卡拉SDK初始化异常", e);
        }
    }
}

支付接口实现

1. 支付Controller (LakalaPayController.java)

package com.shunp.web.controller.pay;
import com.alibaba.fastjson2.JSONObject;
import com.laop.sdk.LKLSDK;
import com.laop.sdk.exception.SDKException;
import com.laop.sdk.request.V3CcssCounterOrderSpecialCreateEncryRequest;
import com.shunp.common.core.controller.BaseController;
import com.shunp.common.core.domain.AjaxResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Calendar;
/**
 * 拉卡拉支付 Controller
 */
@RestController
@RequestMapping("/opmanager/pay/lakala")
@Slf4j
@Tag(name = "拉卡拉支付")
public class LakalaPayController extends BaseController {
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
    /**
     * 收银台订单创建(全报文加密)
     */
    @PostMapping("/counter/order/create/encry")
    @Operation(summary = "收银台订单创建(全报文加密)")
    public AjaxResult createCounterOrderEncry(@RequestBody CounterOrderCreateRequest request) {
        try {
            // 如果前端传入了订单号,使用前端的;否则生成新的
            String orderNo = request.getOutOrderNo() != null && !request.getOutOrderNo().trim().isEmpty()
                    ? request.getOutOrderNo()
                    : generateOrderNo();
            log.info("开始创建收银台订单(全报文加密),订单号:{},商户号:{},交易设备ID:{}",
                    orderNo, request.getMerchantNo(), request.getVposId());
            // 构建请求对象
            V3CcssCounterOrderSpecialCreateEncryRequest lakalaRequest =
                new V3CcssCounterOrderSpecialCreateEncryRequest();
            lakalaRequest.setOutOrderNo(orderNo);
            lakalaRequest.setMerchantNo(request.getMerchantNo());
            lakalaRequest.setVposId(request.getVposId());
            lakalaRequest.setChannelId(request.getChannelId());
            lakalaRequest.setTotalAmount(request.getTotalAmount());
            // 设置订单有效期
            if (request.getOrderEfficientTime() != null) {
                lakalaRequest.setOrderEfficientTime(request.getOrderEfficientTime());
            } else {
                // 默认7天有效期
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.DAY_OF_MONTH, 7);
                lakalaRequest.setOrderEfficientTime(dateFormat.format(calendar.getTime()));
            }
            // 设置回调地址
            lakalaRequest.setNotifyUrl(request.getNotifyUrl());
            lakalaRequest.setOrderInfo(request.getOrderInfo());
            // 调用LKLSDK创建订单
            String response = LKLSDK.httpPost(lakalaRequest, true, true);
            log.info("收银台订单创建完成,响应:{}", response);
            return AjaxResult.success("订单创建成功", response);
        } catch (SDKException e) {
            log.error("收银台订单创建失败,SDK异常:{}", e.getMessage(), e);
            return AjaxResult.error("订单创建失败:" + e.getMessage());
        } catch (Exception e) {
            log.error("收银台订单创建失败,系统异常:{}", e.getMessage(), e);
            return AjaxResult.error("订单创建失败:" + e.getMessage());
        }
    }
    /**
     * 拉卡拉支付回调通知
     */
    @PostMapping("/notify")
    @Operation(summary = "拉卡拉支付回调通知")
    public String paymentNotify(HttpServletRequest request) {
        try {
            log.info("收到拉卡拉支付回调通知");
            // 验证回调签名
            String notifyBody = LKLSDK.notificationHandle(request);
            log.info("回调签名验证成功,通知内容:{}", notifyBody);
            // 解析回调数据
            PaymentNotifyData notifyData = JSONObject.parseObject(notifyBody, PaymentNotifyData.class);
            log.info("支付回调信息 - 商户订单号:{},支付订单号:{},支付状态:{},支付金额:{},支付时间:{}",
                    notifyData.getOutOrderNo(), notifyData.getPayOrderNo(),
                    notifyData.getPayStatus(), notifyData.getPayAmount(), notifyData.getPayTime());
            // 根据业务需求处理回调逻辑(需加订单级锁)
            if ("SUCCESS".equals(notifyData.getPayStatus())) {
                // 支付成功处理
                log.info("支付成功,订单号:{},金额:{}", notifyData.getOutOrderNo(), notifyData.getPayAmount());
                // 这里可以调用业务服务更新订单状态
                // orderService.updateOrderStatus(notifyData.getOutOrderNo(), "PAID");
            } else if ("FAILED".equals(notifyData.getPayStatus())) {
                // 支付失败处理
                log.warn("支付失败,订单号:{}", notifyData.getOutOrderNo());
            } else {
                log.warn("未知支付状态:{},订单号:{}", notifyData.getPayStatus(), notifyData.getOutOrderNo());
            }
            // 返回成功响应给拉卡拉服务器
            return "success";
        } catch (SDKException e) {
            log.error("回调签名验证失败:{}", e.getMessage(), e);
            return "fail";
        } catch (Exception e) {
            log.error("处理支付回调异常:{}", e.getMessage(), e);
            return "fail";
        }
    }
    /**
     * 生成订单号
     */
    private String generateOrderNo() {
        return "LKL" + System.currentTimeMillis() + (int)(Math.random() * 1000);
    }
    /**
     * 收银台订单创建请求DTO
     */
    @Data
    public static class CounterOrderCreateRequest {
        private String outOrderNo;           // 商户订单号
        private String merchantNo;           // 银联商户号
        private String vposId;               // 交易设备标识
        private String channelId;            // 渠道号
        private Long totalAmount;            // 订单金额(单位:分)
        private String orderEfficientTime;   // 订单有效期
        private String notifyUrl;            // 回调地址
        private String orderInfo;            // 订单标题
        private Integer supportCancel;       // 是否支持撤销
        private Integer supportRefund;       // 是否支持退款
        private Integer supportRepeatPay;    // 是否支持多次支付
        private String callbackUrl;          // 前端跳转地址
        private String counterParam;         // 收银台参数
        private String counterRemark;        // 收银台备注
    }
    /**
     * 拉卡拉支付回调数据DTO
     */
    @Data
    public static class PaymentNotifyData {
        private String outOrderNo;       // 商户订单号
        private String payOrderNo;       // 拉卡拉支付订单号
        private String payStatus;        // 支付状态 SUCCESS-成功 FAILED-失败
        private String payAmount;        // 支付金额(单位:分)
        private String payTime;          // 支付完成时间 yyyyMMddHHmmss
        private String merchantNo;       // 商户号
        private String vposId;           // 交易设备标识
        private String payChannel;       // 支付渠道
        private String payMethod;        // 支付方式
        private String attach;           // 附加数据
    }
}

回调处理

回调地址配置

在创建订单时,需要设置回调地址:

// 设置回调地址
lakalaRequest.setNotifyUrl("http://your-domain/opmanager/pay/lakala/notify");

回调数据格式

拉卡拉回调发送的JSON数据格式:

{
    "out_order_no": "LKL1703123456789",
    "pay_order_no": "26011611012001101011002063626",
    "pay_status": "SUCCESS",
    "pay_amount": "1",
    "pay_time": "20260116145443",
    "merchant_no": "8222900701106PZ",
    "vpos_id": "2021052614391",
    "pay_channel": "ALIPAY",
    "pay_method": "SCAN",
    "attach": "附加数据"
}

回调处理逻辑

  1. 签名验证:使用 LKLSDK.notificationHandle() 验证回调签名
  2. 数据解析:将JSON字符串解析为 PaymentNotifyData 对象
  3. 业务处理
    • 支付成功:更新订单状态为已支付
    • 支付失败:记录失败原因
    • 其他状态:记录日志并告警
  4. 响应处理:返回 “success” 告知拉卡拉处理成功

完整代码示例

1. 前端调用示例

// 创建支付订单
const createOrder = async (orderData) => {
    const response = await fetch('/opmanager/pay/lakala/counter/order/create/encry', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            merchantNo: '8222900701106PZ',
            vposId: '2021052614391',
            channelId: '2021052614391',
            totalAmount: 100, // 1元 = 100分
            notifyUrl: 'http://your-domain/opmanager/pay/lakala/notify',
            orderInfo: '商品购买'
        })
    });
    const result = await response.json();
    if (result.code === 200) {
        // 获取支付链接并跳转
        const payUrl = result.data.counter_url;
        window.location.href = payUrl;
    }
};

2. 回调处理业务逻辑示例

@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    /**
     * 更新订单支付状态
     */
    @Transactional
    public void updateOrderStatus(String orderNo, String status) {
        // 加订单级锁防止并发问题
        Order order = orderMapper.selectByOrderNoForUpdate(orderNo);
        if (order != null && "PENDING".equals(order.getStatus())) {
            order.setStatus(status);
            order.setPayTime(new Date());
            orderMapper.updateById(order);
            // 发送支付成功通知
            sendPaymentSuccessNotification(order);
        }
    }
}

注意事项

1. 安全配置

  • ✅ 私钥证书妥善保管,不要在日志中输出
  • ✅ 使用HTTPS协议传输敏感数据
  • ✅ 定期更新证书,避免过期

2. 订单处理

  • ✅ 实现幂等性,避免重复处理同一订单
  • ✅ 添加订单级锁,防止并发更新问题
  • ✅ 记录详细的支付流水日志

3. 异常处理

  • ✅ 妥善处理网络异常和超时
  • ✅ 实现重试机制,但避免无限重试
  • ✅ 监控支付成功率和异常情况

4. 回调处理

  • ✅ 回调接口必须返回 “success”,否则拉卡拉会重试
  • ✅ 回调处理要快速响应,避免超时
  • ✅ 验证回调数据的完整性和正确性

常见问题

Q1: SDK初始化失败怎么处理?

A: 检查配置文件中的证书格式是否正确,私钥是否匹配,网络连接是否正常。

Q2: 订单创建失败的原因?

A: 可能是参数格式错误、金额超出限制、商户状态异常等。检查返回的错误信息。

Q3: 回调没有收到怎么办?

A: 检查回调地址是否正确可访问,防火墙是否阻止了请求,服务器是否正常运行。

Q4: 如何处理重复回调?

A: 在业务逻辑中检查订单状态,只有在特定状态下才处理回调,避免重复处理。

Q5: 支付状态不一致怎么办?

A: 以拉卡拉回调为准,主动查询订单状态进行校对,记录异常情况并告警。

本文档提供完整的拉卡拉支付集成方案,如有问题请参考官方文档或联系技术支持。

总结

到此这篇关于Java对接拉卡拉支付完整指南的文章就介绍到这了,更多相关Java对接拉卡拉支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中的Vector详细解读

    Java中的Vector详细解读

    这篇文章主要介绍了Java中的Vector详细解读,Vector是实现了List接口的子类,其底层是一个对象数组,维护了一个elementData数组,是线程安全的,Vector类的方法带有synchronized关键字,在开发中考虑线程安全中使用Vector,需要的朋友可以参考下
    2023-09-09
  • Java String中移除空白字符的多种方式汇总

    Java String中移除空白字符的多种方式汇总

    这篇文章主要给大家介绍了关于Java String中移除空白字符的多种方式,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Spring定时任务使用及如何使用邮件监控服务器

    Spring定时任务使用及如何使用邮件监控服务器

    这篇文章主要介绍了Spring定时任务使用及如何使用邮件监控服务器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • Java中如何正确遍历删除List中的元素

    Java中如何正确遍历删除List中的元素

    删除List中元素这个场景很场景,很多人可能直接在循环中直接去删除元素,这样做对吗?下面小编就来和大家一起讨论如何正确遍历删除List中的元素,文中有详细的代码示例供大家参考,需要的朋友可以参考下
    2023-11-11
  • IDEA如何解决properties文件乱码问题

    IDEA如何解决properties文件乱码问题

    IDEA编辑器中打开properties文件时出现中文乱码,可以通过修改文件编码格式来解决,具体步骤为:设置》Setting》Editor》FileEncodings,将编码格式更改为UTF-8
    2025-01-01
  • java Executors工具类的相关方法使用创建

    java Executors工具类的相关方法使用创建

    这篇文章主要为大家介绍了java Executors工具类的相关方法使用创建,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • SpringSecurity-2.7中跨域问题解析

    SpringSecurity-2.7中跨域问题解析

    这篇文章主要介绍了SpringSecurity-2.7中跨域问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-01-01
  • mybatis映射表结构的使用

    mybatis映射表结构的使用

    MyBatis通过表结构映射实现数据库操作,本文就来介绍一下mybatis映射表结构的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • SpringBoot中统计方法耗时的七种实现方式小结

    SpringBoot中统计方法耗时的七种实现方式小结

    作为开发者,我们经常需要统计方法的执行时间,以便找出性能瓶颈,优化系统响应速度,今天分享在SpringBoot框架中实现方法耗时统计的几种方法,大家可以根据需求自行选择
    2025-03-03
  • SpringBoot Starter依赖原理与实例详解

    SpringBoot Starter依赖原理与实例详解

    SpringBoot中的starter是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进starter,应用者只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。starter让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰
    2022-09-09

最新评论