手把手教你把三方支付接口打包(Java 版)

之前手把手教大家将三方支付接口打包(TypeScript版)反响还不错,最近在工作中发现,其实还有很多朋友使用的是Java。那么本次,还是以拉卡拉开放平台的接口为例,演示开发JAVA SDK包。

一、开发环境准备

1. 环境配置

确保已安装以下工具:

  • JDK 1.8+(推荐 11)
  • Maven 3.6+
  • IDE(IntelliJ IDEA 或 Eclipse)

检查环境:

bash 复制代码
java -version
mvn -version

2. 创建 Maven 项目

在 IDE 中创建新的 Maven 项目,GroupId 设为com.example,ArtifactId 设为third-party-payment-sdk,版本号1.0.0

项目结构如下:

arduino 复制代码
third-party-payment-sdk/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── config/      // 配置类
│   │   │           ├── api/         // 接口调用类
│   │   │           ├── model/       // 数据模型
│   │   │           └── util/        // 工具类
│   │   └── resources/
│   └── test/
│       └── java/
│           └── com/
│               └── example/
├── pom.xml
└── README.md

3. 配置 pom.xml

添加核心依赖:

bash 复制代码
<dependencies>
    <!-- HTTP客户端 -->
    <dependency>
        <groupId>org.apache.httpcomponents.client5</groupId>
        <artifactId>httpclient5</artifactId>
        <version>5.3</version>
    </dependency>
    
    <!-- JSON处理 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
    
    <!-- 日志 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.9</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.8</version>
        <scope>test</scope>
    </dependency>
    
    <!-- 测试 -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.9.3</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>11</source>
                <target>11</target>
            </configuration>
        </plugin>
    </plugins>
</build>

二、核心功能开发

1. 配置类实现

创建PaymentConfig类管理支付接口的环境配置:

java 复制代码
package com.example.config;

public class PaymentConfig {
    private boolean debug;
    private String appId;
    private String serialNo;
    private String hostPro;
    private String hostTest;
    private String sm4Key;
    private String privateKeyPath;
    private String platformCertPath;

    // 构造器
    public PaymentConfig() {
        // 默认配置
        this.debug = false;
        this.hostPro = "https://s2.lakala.com";
        this.hostTest = "https://test.wsmsd.cn/sit";
    }

    // 获取当前环境主机地址
    public String getHost() {
        return debug ? hostTest : hostPro;
    }

    // Getter和Setter方法
    public boolean isDebug() { return debug; }
    public void setDebug(boolean debug) { this.debug = debug; }
    public String getAppId() { return appId; }
    public void setAppId(String appId) { this.appId = appId; }
    // 其他属性的Getter/Setter省略...
}

2. 数据模型定义

创建请求和响应的实体类,以交易查询为例:

java 复制代码
package com.example.model.request;

import com.fasterxml.jackson.annotation.JsonProperty;

public class TradeQueryRequest {
    @JsonProperty("req_time")
    private String reqTime;
    
    @JsonProperty("version")
    private String version = "3.0";
    
    @JsonProperty("req_data")
    private TradeQueryData reqData;

    // Getter和Setter
    public String getReqTime() { return reqTime; }
    public void setReqTime(String reqTime) { this.reqTime = reqTime; }
    public TradeQueryData getReqData() { return reqData; }
    public void setReqData(TradeQueryData reqData) { this.reqData = reqData; }
}

// 内部数据类
class TradeQueryData {
    @JsonProperty("merchant_no")
    private String merchantNo;
    
    @JsonProperty("term_no")
    private String termNo;
    
    @JsonProperty("out_trade_no")
    private String outTradeNo;
    
    @JsonProperty("trade_no")
    private String tradeNo;

    // Getter和Setter省略...
}

响应模型:

java 复制代码
package com.example.model.response;

import com.fasterxml.jackson.annotation.JsonProperty;

public class PaymentResponse<T> {
    @JsonProperty("code")
    private int code;
    
    @JsonProperty("message")
    private String message;
    
    @JsonProperty("data")
    private T data;

    // Getter和Setter
    public boolean isSuccess() {
        return code == 0;
    }
    // 其他Getter/Setter省略...
}

3. 接口调用核心类

实现PaymentClient类封装 HTTP 请求逻辑:

java 复制代码
package com.example.api;

import com.example.config.PaymentConfig;
import com.example.model.response.PaymentResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.hc.client5.http.fluent.Request;
import org.apache.hc.core5.http.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PaymentClient {
    private static final Logger logger = LoggerFactory.getLogger(PaymentClient.class);
    private final PaymentConfig config;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public PaymentClient(PaymentConfig config) {
        this.config = config;
    }

    /**
     * 发送POST请求
     */
    public <T, R> PaymentResponse<R> post(String path, T request, Class<R> responseDataClass) {
        try {
            // 1. 构建URL
            String url = config.getHost() + path;
            
            // 2. 转换请求对象为JSON
            String requestJson = objectMapper.writeValueAsString(request);
            logger.info("请求URL: {}, 参数: {}", url, requestJson);
            
            // 3. 发送请求
            String responseJson = Request.post(url)
                    .bodyString(requestJson, ContentType.APPLICATION_JSON)
                    .execute()
                    .returnContent()
                    .asString();
            
            logger.info("响应: {}", responseJson);
            
            // 4. 解析响应
            return objectMapper.readValue(responseJson, 
                objectMapper.getTypeFactory().constructParametricType(PaymentResponse.class, responseDataClass));
        } catch (Exception e) {
            logger.error("请求异常", e);
            throw new RuntimeException("接口调用失败", e);
        }
    }
}

4. 工具类实现

创建PaymentUtils处理时间、签名等通用逻辑:

java 复制代码
package com.example.util;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
import java.security.MessageDigest;

public class PaymentUtils {
    /**
     * 生成格式为YYYYMMDDHHmmss的时间戳
     */
    public static String getCurrentTime() {
        return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
    }

    /**
     * 生成签名
     */
    public static String generateSign(Map<String, String> params, String secret) {
        // 1. 参数排序
        Map<String, String> sortedParams = new TreeMap<>(params);
        
        // 2. 拼接参数
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
        }
        sb.append("secret=").append(secret);
        
        // 3. 计算MD5
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(sb.toString().getBytes("UTF-8"));
            
            // 转换为十六进制字符串
            StringBuilder result = new StringBuilder();
            for (byte b : bytes) {
                String hex = Integer.toHexString(b & 0xFF);
                if (hex.length() == 1) {
                    result.append("0");
                }
                result.append(hex);
            }
            return result.toString().toUpperCase();
        } catch (Exception e) {
            throw new RuntimeException("签名生成失败", e);
        }
    }
}

三、接口封装示例

以交易查询接口为例,创建专用的 API 类:

java 复制代码
package com.example.api;

import com.example.model.request.TradeQueryRequest;
import com.example.model.request.TradeQueryData;
import com.example.model.response.PaymentResponse;
import com.example.model.response.TradeQueryResponseData;
import com.example.util.PaymentUtils;

public class TradeApi {
    private final PaymentClient client;

    public TradeApi(PaymentClient client) {
        this.client = client;
    }

    /**
     * 查询交易
     */
    public PaymentResponse<TradeQueryResponseData> queryTrade(String merchantNo, String outTradeNo) {
        // 1. 构建请求参数
        TradeQueryRequest request = new TradeQueryRequest();
        request.setReqTime(PaymentUtils.getCurrentTime());
        
        TradeQueryData data = new TradeQueryData();
        data.setMerchantNo(merchantNo);
        data.setOutTradeNo(outTradeNo);
        request.setReqData(data);
        
        // 2. 调用接口
        return client.post("/api/v3/labs/query/tradequery", 
                request, TradeQueryResponseData.class);
    }
}

四、单元测试

编写测试类验证功能:

java 复制代码
package com.example.api;

import com.example.config.PaymentConfig;
import com.example.model.response.PaymentResponse;
import com.example.model.response.TradeQueryResponseData;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class TradeApiTest {
    private TradeApi tradeApi;

    @BeforeEach
    void setUp() {
        // 初始化配置
        PaymentConfig config = new PaymentConfig();
        config.setDebug(true); // 测试环境
        config.setAppId("你的appId");
        config.setSerialNo("你的serialNo");
        
        // 创建客户端
        PaymentClient client = new PaymentClient(config);
        tradeApi = new TradeApi(client);
    }

    @Test
    void testQueryTrade() {
        PaymentResponse<TradeQueryResponseData> response = 
            tradeApi.queryTrade("822290070111135", "TEST" + System.currentTimeMillis());
        
        assertTrue(response.isSuccess(), "查询失败: " + response.getMessage());
        System.out.println("交易状态: " + response.getData().getTradeStatus());
    }
}

五、打包与发布

1. 打包为 JAR

执行 Maven 命令打包:

bash 复制代码
mvn clean package

生成的 JAR 包位于target/目录下。

2. 发布到 Maven 仓库(可选)

配置pom.xml中的分发仓库信息,然后执行:

bash 复制代码
mvn deploy

六、SDK 使用示例

其他项目引入 SDK 后,使用方式如下:

java 复制代码
import com.example.api.TradeApi;
import com.example.api.PaymentClient;
import com.example.config.PaymentConfig;
import com.example.model.response.PaymentResponse;
import com.example.model.response.TradeQueryResponseData;

public class PaymentDemo {
    public static void main(String[] args) {
        // 1. 初始化配置
        PaymentConfig config = new PaymentConfig();
        config.setDebug(false); // 生产环境
        config.setAppId("你的appId");
        config.setSerialNo("你的serialNo");
        
        // 2. 创建客户端和API实例
        PaymentClient client = new PaymentClient(config);
        TradeApi tradeApi = new TradeApi(client);
        
        // 3. 调用接口
        try {
            PaymentResponse<TradeQueryResponseData> response = 
                tradeApi.queryTrade("商户号", "订单号");
            
            if (response.isSuccess()) {
                System.out.println("查询成功,交易号: " + response.getData().getTradeNo());
            } else {
                System.err.println("查询失败: " + response.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

总结

本文通过 Java 实现了三方支付接口的 SDK 封装,涵盖了配置管理、数据模型、HTTP 通信、签名工具等核心模块。使用 SDK 可以屏蔽支付接口的底层细节,让开发者专注于业务逻辑。实际开发中,可根据具体支付平台的接口文档(如文档中心)扩展更多功能,如退款、订单创建等接口封装。

通过标准化的 SDK 开发,不仅能提高团队协作效率,还能降低对接多个支付渠道的维护成本,是企业级支付系统开发的最佳实践。

PS: 其实官方已经有JAVA版的SDK供大家使用了,大家可以对比着来看~~~


手把手教你把三方支付接口打包成 TypeScript SDK

拉卡拉开放平台

文档中心

相关推荐
笑衬人心。13 分钟前
缓存的三大问题分析与解决
java·spring·缓存
用户84913717547161 小时前
JDK 17 实战系列(第7期):迁移指南与最佳实践
java·jvm
duration~1 小时前
SpringAI实现Reread(Advisor)
java·人工智能·spring boot·spring
我们从未走散1 小时前
面试题-----微服务业务
java·开发语言·微服务·架构
YuforiaCode1 小时前
24SpringCloud黑马商城微服务整合Seata重启服务报错的解决办法
java·spring·微服务
考虑考虑1 小时前
JDK21中的Sequenced Collections(序列集合)
java·后端·java ee
一 乐2 小时前
心理咨询|学生心理咨询评估系统|基于Springboot的学生心理咨询评估系统设计与实现(源码+数据库+文档)
java·数据库·spring boot·后端·论文·毕设·学生心理咨询评估系统
Java技术小馆2 小时前
Gemini Storybook AI驱动的交互式故事创作
java·程序员·架构
码神本神3 小时前
(附源码)基于Spring Boot的4S店信息管理系统 的设计与实现
java·spring boot·后端